Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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-18/lib/clang/18 -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/QtMultimedia -isystem /usr/include/x86_64-linux-gnu/qt6/QtNetwork -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-18/lib/clang/18/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-truncation -Wno-format-nonliteral -std=c++17 -fdeprecated-macro -ferror-limit 19 -fwrapv -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 -dwarf-debug-flags /usr/lib/llvm-18/bin/clang --driver-mode=g++ -### --analyze -x c++ -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 -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/QtMultimedia -isystem /usr/include/x86_64-linux-gnu/qt6/QtNetwork -isystem /usr/include/x86_64-linux-gnu/qt6/QtDBus -fexcess-precision=fast -fstrict-flex-arrays=3 -fstack-clash-protection -fcf-protection=full -D _GLIBCXX_ASSERTIONS -fstack-protector-strong -fno-delete-null-pointer-checks -fno-strict-overflow -fno-strict-aliasing -fexceptions -Wno-format-truncation -Wno-format-nonliteral -fdiagnostics-color=always -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -std=c++17 -fPIC -fPIC /builds/wireshark/wireshark/ui/qt/simple_statistics_dialog.cpp -o /builds/wireshark/wireshark/sbout/2025-01-04-100244-3868-1 -Xclang -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-01-04-100244-3868-1 -x c++ /builds/wireshark/wireshark/ui/qt/simple_statistics_dialog.cpp
1/* simple_statistics_dialog.cpp
2 *
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <[email protected]>
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
23static QHash<const QString, stat_tap_table_ui *> cfg_str_to_stu_;
24
25extern "C" {
26static void
27simple_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}
39
40bool register_simple_stat_tables(const void *key, void *value, void*) {
41 stat_tap_table_ui *stu = (stat_tap_table_ui*)value;
42
43 cfg_str_to_stu_[stu->cli_string] = stu;
44 TapParameterDialog::registerDialog(
45 stu->title,
46 (const char*)key,
47 stu->group,
48 simple_stat_init,
49 SimpleStatisticsDialog::createSimpleStatisticsDialog);
50 return false;
51}
52
53enum {
54 simple_row_type_ = 1000
55};
56
57class SimpleStatisticsTreeWidgetItem : public QTreeWidgetItem
58{
59public:
60 SimpleStatisticsTreeWidgetItem(QTreeWidgetItem *parent, int num_fields, const stat_tap_table_item_type *fields, const stat_tap_table_item *field) :
61 QTreeWidgetItem (parent, simple_row_type_),
62 num_fields_(num_fields),
63 fields_(fields),
64 field_(field)
65 {
66 }
67 void draw() {
68 for (int i = 0; i < num_fields_ && i < treeWidget()->columnCount(); i++) {
69 switch (fields_[i].type) {
70 case TABLE_ITEM_UINT:
71 setText(i, QString::asprintf(field_[i].field_format, fields_[i].value.uint_value));
72 break;
73 case TABLE_ITEM_INT:
74 setText(i, QString::asprintf(field_[i].field_format, fields_[i].value.int_value));
75 break;
76 case TABLE_ITEM_STRING:
77 setText(i, QString::asprintf(field_[i].field_format, fields_[i].value.string_value));
78 break;
79 case TABLE_ITEM_FLOAT:
80 setText(i, QString::asprintf(field_[i].field_format, fields_[i].value.float_value));
81 break;
82 case TABLE_ITEM_ENUM:
83 setText(i, QString::number(fields_[i].value.enum_value));
84 break;
85 default:
86 break;
87 }
88 }
89 }
90 bool operator< (const QTreeWidgetItem &other) const
91 {
92 int col = treeWidget()->sortColumn();
93 if (other.type() != simple_row_type_ || col >= num_fields_) {
94 return QTreeWidgetItem::operator< (other);
95 }
96 const SimpleStatisticsTreeWidgetItem *other_row = static_cast<const SimpleStatisticsTreeWidgetItem *>(&other);
97 switch (fields_[col].type) {
98 case TABLE_ITEM_UINT:
99 return fields_[col].value.uint_value < other_row->fields_[col].value.uint_value;
100 case TABLE_ITEM_INT:
101 return fields_[col].value.int_value < other_row->fields_[col].value.int_value;
102 case TABLE_ITEM_STRING:
103 return g_strcmp0(fields_[col].value.string_value, other_row->fields_[col].value.string_value) < 0;
104 case TABLE_ITEM_FLOAT:
105 return fields_[col].value.float_value < other_row->fields_[col].value.float_value;
106 case TABLE_ITEM_ENUM:
107 return fields_[col].value.enum_value < other_row->fields_[col].value.enum_value;
108 default:
109 break;
110 }
111
112 return QTreeWidgetItem::operator< (other);
113 }
114 QList<QVariant> rowData() {
115 QList<QVariant> row_data;
116
117 for (int i = 0; i < num_fields_ && i < columnCount(); i++) {
118 switch (fields_[i].type) {
119 case TABLE_ITEM_UINT:
120 row_data << fields_[i].value.uint_value;
121 break;
122 case TABLE_ITEM_INT:
123 row_data << fields_[i].value.int_value;
124 break;
125 case TABLE_ITEM_STRING:
126 row_data << fields_[i].value.string_value;
127 break;
128 case TABLE_ITEM_FLOAT:
129 row_data << fields_[i].value.float_value;
130 break;
131 case TABLE_ITEM_ENUM:
132 row_data << fields_[i].value.enum_value;
133 break;
134 default:
135 break;
136 }
137 }
138
139 return row_data;
140 }
141
142private:
143 const int num_fields_;
144 const stat_tap_table_item_type *fields_;
145 const stat_tap_table_item *field_;
146};
147
148SimpleStatisticsDialog::SimpleStatisticsDialog(QWidget &parent, CaptureFile &cf, struct _stat_tap_table_ui *stu, const QString filter, int help_topic) :
149 TapParameterDialog(parent, cf, help_topic),
150 stu_(stu)
151{
152 stu->refcount++;
153 setWindowSubtitle(stu_->title);
154 loadGeometry(0, 0, stu_->title);
155
156 QStringList header_labels;
157 for (int col = 0; col < (int) stu_->nfields; col++) {
158 header_labels << stu_->fields[col].column_name;
159 }
160 statsTreeWidget()->setHeaderLabels(header_labels);
161
162 for (int col = 0; col < (int) stu_->nfields; col++) {
163 if (stu_->fields[col].align == TAP_ALIGN_RIGHT) {
164 statsTreeWidget()->headerItem()->setTextAlignment(col, Qt::AlignRight);
165 }
166 }
167
168 setDisplayFilter(filter);
169}
170
171TapParameterDialog *SimpleStatisticsDialog::createSimpleStatisticsDialog(QWidget &parent, const QString cfg_str, const QString filter, CaptureFile &cf)
172{
173 if (!cfg_str_to_stu_.contains(cfg_str)) {
174 // XXX MessageBox?
175 return NULL__null;
176 }
177
178 stat_tap_table_ui *stu = cfg_str_to_stu_[cfg_str];
179
180 return new SimpleStatisticsDialog(parent, cf, stu, filter);
181}
182
183void SimpleStatisticsDialog::addMissingRows(struct _stat_data_t *stat_data)
184{
185 // Hierarchy:
186 // - tables (GTK+ UI only supports one currently)
187 // - elements (rows?)
188 // - fields (columns?)
189 // For multiple table support we might want to add them as subtrees, with
190 // the top-level tree item text set to the column labels for that table.
191
192 // Add any missing tables and rows.
193 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
194 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)])
;
195 QTreeWidgetItem *ti = NULL__null;
196
197 if ((int) table_idx >= statsTreeWidget()->topLevelItemCount()) {
11
Assuming the condition is false
12
Taking false branch
198 ti = new QTreeWidgetItem(statsTreeWidget());
199 ti->setText(0, st_table->title);
200 ti->setFirstColumnSpanned(true);
201 ti->setExpanded(true);
202 } else {
203 ti = statsTreeWidget()->topLevelItem(table_idx);
204 }
205 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'
206 stat_tap_table_item_type* fields = stat_tap_get_field_data(st_table, element, 0);
207 if (stu_->nfields > 0) {
15
Assuming field 'nfields' is > 0
16
Taking true branch
208 SimpleStatisticsTreeWidgetItem *ss_ti = new SimpleStatisticsTreeWidgetItem(ti, st_table->num_fields, fields, stu_->fields);
17
Memory is allocated
209 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 continues on line 205
210 if (stu_->fields[col].align == TAP_ALIGN_RIGHT) {
19
Assuming field 'align' is not equal to TAP_ALIGN_RIGHT
20
Taking false branch
211 ss_ti->setTextAlignment(col, Qt::AlignRight);
212 }
213 }
214 }
215 }
216 }
217}
218
219void SimpleStatisticsDialog::tapReset(void *sd_ptr)
220{
221 stat_data_t *sd = (stat_data_t*) sd_ptr;
222 SimpleStatisticsDialog *ss_dlg = static_cast<SimpleStatisticsDialog *>(sd->user_data);
223 if (!ss_dlg) return;
224
225 reset_stat_table(sd->stat_tap_data);
226 ss_dlg->statsTreeWidget()->clear();
227}
228
229void SimpleStatisticsDialog::tapDraw(void *sd_ptr)
230{
231 stat_data_t *sd = (stat_data_t*) sd_ptr;
232 SimpleStatisticsDialog *ss_dlg = static_cast<SimpleStatisticsDialog *>(sd->user_data);
233 if (!ss_dlg) return;
6
Assuming 'ss_dlg' is non-null
7
Taking false branch
234
235 ss_dlg->addMissingRows(sd);
8
Calling 'SimpleStatisticsDialog::addMissingRows'
236
237 QTreeWidgetItemIterator it(ss_dlg->statsTreeWidget());
238 while (*it) {
239 if ((*it)->type() == simple_row_type_) {
240 SimpleStatisticsTreeWidgetItem *ss_ti = static_cast<SimpleStatisticsTreeWidgetItem *>((*it));
241 ss_ti->draw();
242 }
243 ++it;
244 }
245
246 for (int i = 0; i < ss_dlg->statsTreeWidget()->columnCount() - 1; i++) {
247 ss_dlg->statsTreeWidget()->resizeColumnToContents(i);
248 }
249}
250
251void SimpleStatisticsDialog::fillTree()
252{
253 stat_data_t stat_data;
254 stat_data.stat_tap_data = stu_;
255 stat_data.user_data = this;
256
257 stu_->stat_tap_init_cb(stu_);
258
259 QString display_filter = displayFilter();
260 if (!registerTapListener(stu_->tap_name,
1
Assuming the condition is false
2
Taking false branch
261 &stat_data,
262 display_filter.toUtf8().constData(),
263 0,
264 tapReset,
265 stu_->packet_func,
266 tapDraw)) {
267 free_stat_tables(stu_);
268 reject(); // XXX Stay open instead?
269 return;
270 }
271
272 statsTreeWidget()->setSortingEnabled(false);
273
274 cap_file_.retapPackets();
275
276 // We only have one table. Move its tree items up one level.
277 if (statsTreeWidget()->invisibleRootItem()->childCount() == 1) {
3
Assuming the condition is false
4
Taking false branch
278 statsTreeWidget()->setRootIndex(statsTreeWidget()->model()->index(0, 0));
279 }
280
281 tapDraw(&stat_data);
5
Calling 'SimpleStatisticsDialog::tapDraw'
282
283 statsTreeWidget()->sortItems(0, Qt::AscendingOrder);
284 statsTreeWidget()->setSortingEnabled(true);
285
286 removeTapListeners();
287}
288
289// This is how an item is represented for exporting.
290QList<QVariant> SimpleStatisticsDialog::treeItemData(QTreeWidgetItem *it) const
291{
292 // Cast up to our type.
293 SimpleStatisticsTreeWidgetItem *rit = dynamic_cast<SimpleStatisticsTreeWidgetItem*>(it);
294 if (rit) {
295 return rit->rowData();
296 }
297 else {
298 return QList<QVariant>();
299 }
300}
301
302
303SimpleStatisticsDialog::~SimpleStatisticsDialog()
304{
305 stu_->refcount--;
306 if (stu_->refcount == 0) {
307 if (stu_->tables)
308 free_stat_tables(stu_);
309 }
310}