### Bug Summary

File: | builds/wireshark/wireshark/ui/qt/simple_statistics_dialog.cpp
Warning: | line 207, column 85 Potential leak of memory pointed to by 'ss_ti'

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name simple_statistics_dialog.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/build/ui/qt -isystem /builds/wireshark/wireshark/ui/qt -isystem /usr/include/x86_64-linux-gnu/qt6/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt6 -isystem /usr/include/x86_64-linux-gnu/qt6/QtCore -isystem /usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++ -isystem /usr/include/x86_64-linux-gnu/qt6/QtGui -isystem /usr/include/x86_64-linux-gnu/qt6/QtCore5Compat -isystem /usr/include/x86_64-linux-gnu/qt6/QtConcurrent -isystem /usr/include/x86_64-linux-gnu/qt6/QtPrintSupport -isystem /usr/include/x86_64-linux-gnu/qt6/QtNetwork -isystem /usr/include/x86_64-linux-gnu/qt6/QtMultimedia -isystem /usr/include/x86_64-linux-gnu/qt6/QtDBus -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D QT_CONCURRENT_LIB -D QT_CORE5COMPAT_LIB -D QT_CORE_LIB -D QT_DBUS_LIB -D QT_GUI_LIB -D QT_MULTIMEDIA_LIB -D QT_NETWORK_LIB -D QT_PRINTSUPPORT_LIB -D QT_WIDGETS_LIB -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build/ui/qt/qtui_autogen/include -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=c++17 -fdeprecated-macro -ferror-limit 19 -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2026-04-16-100347-3641-1 -x c++ /builds/wireshark/wireshark/ui/qt/simple_statistics_dialog.cpp

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /* simple_statistics_dialog.cpp
2 | *
3 | * Wireshark - Network traffic analyzer
4 | * By Gerald Combs <gerald@wireshark.org>
5 | * Copyright 1998 Gerald Combs
6 | *
7 | * SPDX-License-Identifier: GPL-2.0-or-later
8 | */
9 |
10 | #include "simple_statistics_dialog.h"
11 |
12 | #include "file.h"
13 |
14 | #include "epan/stat_tap_ui.h"
15 |
16 | #include <QTreeWidget>
17 |
18 | #include "main_application.h"
19 |
20 | // To do:
21 | // - Hide rows with zero counts.
22 |
23 | static QHash<const QString, stat_tap_table_ui *> cfg_str_to_stu_;
24 |
25 | extern "C" {
26 | static bool
27 | simple_stat_init(const char *args, void*) {
28 | QStringList args_l = QString(args).split(',');
29 | if (args_l.length() > 1) {
30 | QString simple_stat = QStringLiteral("%1,%2")(QString(QtPrivate::qMakeStringPrivate(u"" "%1,%2"))).arg(args_l[0]).arg(args_l[1]);
31 | QString filter;
32 | if (args_l.length() > 2) {
33 | filter = QStringList(args_l.mid(2)).join(",");
34 | }
35 | mainApp->emitTapParameterSignal(simple_stat, filter, NULL__null);
36 | }
37 |
38 | return true;
39 | }
40 | }
41 |
42 | bool register_simple_stat_tables(const void *key, void *value, void*) {
43 | stat_tap_table_ui *stu = (stat_tap_table_ui*)value;
44 |
45 | cfg_str_to_stu_[stu->cli_string] = stu;
46 | TapParameterDialog::registerDialog(
47 | stu->title,
48 | (const char*)key,
49 | stu->group,
50 | simple_stat_init,
51 | SimpleStatisticsDialog::createSimpleStatisticsDialog);
52 | return false;
53 | }
54 |
55 | enum {
56 | simple_row_type_ = 1000
57 | };
58 |
59 | class SimpleStatisticsTreeWidgetItem : public QTreeWidgetItem
60 | {
61 | public:
62 | SimpleStatisticsTreeWidgetItem(QTreeWidgetItem *parent, int num_fields, const stat_tap_table_item_type *fields, const stat_tap_table_item *field) :
63 | QTreeWidgetItem (parent, simple_row_type_),
64 | num_fields_(num_fields),
65 | fields_(fields),
66 | field_(field)
67 | {
68 | }
69 | void draw() {
70 | for (int i = 0; i < num_fields_ && i < treeWidget()->columnCount(); i++) {
71 | switch (fields_[i].type) {
72 | case TABLE_ITEM_UINT:
73 | setText(i, QString::asprintf(field_[i].field_format, fields_[i].value.uint_value));
74 | break;
75 | case TABLE_ITEM_INT:
76 | setText(i, QString::asprintf(field_[i].field_format, fields_[i].value.int_value));
77 | break;
78 | case TABLE_ITEM_STRING:
79 | setText(i, QString::asprintf(field_[i].field_format, fields_[i].value.string_value));
80 | break;
81 | case TABLE_ITEM_FLOAT:
82 | setText(i, QString::asprintf(field_[i].field_format, fields_[i].value.float_value));
83 | break;
84 | case TABLE_ITEM_ENUM:
85 | setText(i, QString::number(fields_[i].value.enum_value));
86 | break;
87 | default:
88 | break;
89 | }
90 | }
91 | }
92 | bool operator< (const QTreeWidgetItem &other) const
93 | {
94 | int col = treeWidget()->sortColumn();
95 | if (other.type() != simple_row_type_ || col >= num_fields_) {
96 | return QTreeWidgetItem::operator< (other);
97 | }
98 | const SimpleStatisticsTreeWidgetItem *other_row = static_cast<const SimpleStatisticsTreeWidgetItem *>(&other);
99 | switch (fields_[col].type) {
100 | case TABLE_ITEM_UINT:
101 | return fields_[col].value.uint_value < other_row->fields_[col].value.uint_value;
102 | case TABLE_ITEM_INT:
103 | return fields_[col].value.int_value < other_row->fields_[col].value.int_value;
104 | case TABLE_ITEM_STRING:
105 | return g_strcmp0(fields_[col].value.string_value, other_row->fields_[col].value.string_value) < 0;
106 | case TABLE_ITEM_FLOAT:
107 | return fields_[col].value.float_value < other_row->fields_[col].value.float_value;
108 | case TABLE_ITEM_ENUM:
109 | return fields_[col].value.enum_value < other_row->fields_[col].value.enum_value;
110 | default:
111 | break;
112 | }
113 |
114 | return QTreeWidgetItem::operator< (other);
115 | }
116 | QList<QVariant> rowData() {
117 | QList<QVariant> row_data;
118 |
119 | for (int i = 0; i < num_fields_ && i < columnCount(); i++) {
120 | switch (fields_[i].type) {
121 | case TABLE_ITEM_UINT:
122 | row_data << fields_[i].value.uint_value;
123 | break;
124 | case TABLE_ITEM_INT:
125 | row_data << fields_[i].value.int_value;
126 | break;
127 | case TABLE_ITEM_STRING:
128 | row_data << fields_[i].value.string_value;
129 | break;
130 | case TABLE_ITEM_FLOAT:
131 | row_data << fields_[i].value.float_value;
132 | break;
133 | case TABLE_ITEM_ENUM:
134 | row_data << fields_[i].value.enum_value;
135 | break;
136 | default:
137 | break;
138 | }
139 | }
140 |
141 | return row_data;
142 | }
143 |
144 | private:
145 | const int num_fields_;
146 | const stat_tap_table_item_type *fields_;
147 | const stat_tap_table_item *field_;
148 | };
149 |
150 | SimpleStatisticsDialog::SimpleStatisticsDialog(QWidget &parent, CaptureFile &cf, struct _stat_tap_table_ui *stu, const QString filter, int help_topic) :
151 | TapParameterDialog(parent, cf, help_topic),
152 | stu_(stu)
153 | {
154 | stu->refcount++;
155 | setWindowSubtitle(stu_->title);
156 | loadGeometry(0, 0, stu_->title);
157 |
158 | QStringList header_labels;
159 | for (int col = 0; col < (int) stu_->nfields; col++) {
160 | header_labels << stu_->fields[col].column_name;
161 | }
162 | statsTreeWidget()->setHeaderLabels(header_labels);
163 |
164 | for (int col = 0; col < (int) stu_->nfields; col++) {
165 | if (stu_->fields[col].align == TAP_ALIGN_RIGHT) {
166 | statsTreeWidget()->headerItem()->setTextAlignment(col, Qt::AlignRight);
167 | }
168 | }
169 |
170 | setDisplayFilter(filter);
171 | }
172 |
173 | TapParameterDialog *SimpleStatisticsDialog::createSimpleStatisticsDialog(QWidget &parent, const QString cfg_str, const QString filter, CaptureFile &cf)
174 | {
175 | if (!cfg_str_to_stu_.contains(cfg_str)) {
176 | // XXX MessageBox?
177 | return NULL__null;
178 | }
179 |
180 | stat_tap_table_ui *stu = cfg_str_to_stu_[cfg_str];
181 |
182 | return new SimpleStatisticsDialog(parent, cf, stu, filter);
183 | }
184 |
185 | void SimpleStatisticsDialog::addMissingRows(struct _stat_data_t *stat_data)
186 | {
187 | // Hierarchy:
188 | // - tables (GTK+ UI only supports one currently)
189 | // - elements (rows?)
190 | // - fields (columns?)
191 | // For multiple table support we might want to add them as subtrees, with
192 | // the top-level tree item text set to the column labels for that table.
193 |
194 | // Add any missing tables and rows.
195 | for (unsigned table_idx = 0; table_idx < stat_data->stat_tap_data->tables->len; table_idx++) {
9 | ← | Assuming 'table_idx' is < field 'len' | →
10 | ← | Loop condition is true. Entering loop body | →
196 | stat_tap_table* st_table = g_array_index(stat_data->stat_tap_data->tables, stat_tap_table*, table_idx)(((stat_tap_table**) (void *) (stat_data->stat_tap_data-> tables)->data) [(table_idx)]);
197 | QTreeWidgetItem *ti = NULL__null;
198 |
199 | if ((int) table_idx >= statsTreeWidget()->topLevelItemCount()) {
11 | ← | Assuming the condition is false | →
12 | ← | Taking false branch | →
200 | ti = new QTreeWidgetItem(statsTreeWidget());
201 | ti->setText(0, st_table->title);
202 | ti->setFirstColumnSpanned(true);
203 | ti->setExpanded(true);
204 | } else {
205 | ti = statsTreeWidget()->topLevelItem(table_idx);
206 | }
207 | for (unsigned element = ti->childCount(); element < st_table->num_elements; element++) {
13 | ← | Assuming 'element' is < field 'num_elements' | →
14 | ← | Loop condition is true. Entering loop body | →
23 | ← | Potential leak of memory pointed to by 'ss_ti'
208 | stat_tap_table_item_type* fields = stat_tap_get_field_data(st_table, element, 0);
209 | if (stu_->nfields > 0) {
15 | ← | Assuming field 'nfields' is > 0 | →
16 | ← | Taking true branch | →
210 | SimpleStatisticsTreeWidgetItem *ss_ti = new SimpleStatisticsTreeWidgetItem(ti, st_table->num_fields, fields, stu_->fields);
17 | ← | Memory is allocated | →
211 | for (int col = 0; col
17.1 | 'col' is < field 'nfields'
< (int) stu_->nfields; col++) {
18 | ← | Loop condition is true. Entering loop body | →
21 | ← | Assuming 'col' is >= field 'nfields' | →
22 | ← | Loop condition is false. Execution jumps to the end of the function | →
212 | if (stu_->fields[col].align == TAP_ALIGN_RIGHT) {
19 | ← | Assuming field 'align' is not equal to TAP_ALIGN_RIGHT | →
20 | ← | Taking false branch | →
213 | ss_ti->setTextAlignment(col, Qt::AlignRight);
214 | }
215 | }
216 | }
217 | }
218 | }
219 | }
220 |
221 | void SimpleStatisticsDialog::tapReset(void *sd_ptr)
222 | {
223 | stat_data_t *sd = (stat_data_t*) sd_ptr;
224 | SimpleStatisticsDialog *ss_dlg = static_cast<SimpleStatisticsDialog *>(sd->user_data);
225 | if (!ss_dlg) return;
226 |
227 | reset_stat_table(sd->stat_tap_data);
228 | ss_dlg->statsTreeWidget()->clear();
229 | }
230 |
231 | void SimpleStatisticsDialog::tapDraw(void *sd_ptr)
232 | {
233 | stat_data_t *sd = (stat_data_t*) sd_ptr;
234 | SimpleStatisticsDialog *ss_dlg = static_cast<SimpleStatisticsDialog *>(sd->user_data);
235 | if (!ss_dlg) return;
6 | ← | Assuming 'ss_dlg' is non-null | →
7 | ← | Taking false branch | →
236 |
237 | ss_dlg->addMissingRows(sd);
8 | ← | Calling 'SimpleStatisticsDialog::addMissingRows' | →
238 |
239 | QTreeWidgetItemIterator it(ss_dlg->statsTreeWidget());
240 | while (*it) {
241 | if ((*it)->type() == simple_row_type_) {
242 | SimpleStatisticsTreeWidgetItem *ss_ti = static_cast<SimpleStatisticsTreeWidgetItem *>((*it));
243 | ss_ti->draw();
244 | }
245 | ++it;
246 | }
247 |
248 | for (int i = 0; i < ss_dlg->statsTreeWidget()->columnCount() - 1; i++) {
249 | ss_dlg->statsTreeWidget()->resizeColumnToContents(i);
250 | }
251 | }
252 |
253 | void SimpleStatisticsDialog::fillTree()
254 | {
255 | stat_data_t stat_data;
256 | stat_data.stat_tap_data = stu_;
257 | stat_data.user_data = this;
258 |
259 | stu_->stat_tap_init_cb(stu_);
260 |
261 | QString display_filter = displayFilter();
262 | if (!registerTapListener(stu_->tap_name,
1 | Assuming the condition is false | →
2 | ← | Taking false branch | →
263 | &stat_data,
264 | display_filter.toUtf8().constData(),
265 | 0,
266 | tapReset,
267 | stu_->packet_func,
268 | tapDraw)) {
269 | free_stat_tables(stu_);
270 | reject(); // XXX Stay open instead?
271 | return;
272 | }
273 |
274 | statsTreeWidget()->setSortingEnabled(false);
275 |
276 | cap_file_.retapPackets();
277 |
278 | // We only have one table. Move its tree items up one level.
279 | if (statsTreeWidget()->invisibleRootItem()->childCount() == 1) {
3 | ← | Assuming the condition is false | →
4 | ← | Taking false branch | →
280 | statsTreeWidget()->setRootIndex(statsTreeWidget()->model()->index(0, 0));
281 | }
282 |
283 | tapDraw(&stat_data);
5 | ← | Calling 'SimpleStatisticsDialog::tapDraw' | →
284 |
285 | statsTreeWidget()->sortItems(0, Qt::AscendingOrder);
286 | statsTreeWidget()->setSortingEnabled(true);
287 |
288 | removeTapListeners();
289 | }
290 |
291 | // This is how an item is represented for exporting.
292 | QList<QVariant> SimpleStatisticsDialog::treeItemData(QTreeWidgetItem *it) const
293 | {
294 | // Cast up to our type.
295 | SimpleStatisticsTreeWidgetItem *rit = dynamic_cast<SimpleStatisticsTreeWidgetItem*>(it);
296 | if (rit) {
297 | return rit->rowData();
298 | }
299 | else {
300 | return QList<QVariant>();
301 | }
302 | }
303 |
304 |
305 | SimpleStatisticsDialog::~SimpleStatisticsDialog()
306 | {
307 | stu_->refcount--;
308 | if (stu_->refcount == 0) {
309 | if (stu_->tables)
310 | free_stat_tables(stu_);
311 | }
312 | }