### Bug Summary

File: | epan/funnel.c
Warning: | line 100, column 26 Use of memory after it is freed

### 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 funnel.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -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/epan -isystem /builds/wireshark/wireshark/build/epan -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /usr/include/lua5.4 -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D epan_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -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=gnu11 -ferror-limit 19 -fvisibility=hidden -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 -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-12-12-100324-3573-1 -x c /builds/wireshark/wireshark/epan/funnel.c

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 | /*
2 | * funnel.c
3 | *
4 | * EPAN's GUI mini-API
5 | *
6 | * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
7 | *
8 | * Wireshark - Network traffic analyzer
9 | * By Gerald Combs <gerald@wireshark.org>
10 | * Copyright 1998 Gerald Combs
11 | *
12 | * SPDX-License-Identifier: GPL-2.0-or-later
13 | */
14 |
15 | #include "config.h"
16 |
17 | #include <epan/funnel.h>
18 | #include <wsutil/glib-compat.h>
19 |
20 | typedef struct _funnel_menu_t {
21 | char *name;
22 | register_stat_group_t group;
23 | funnel_menu_callback callback;
24 | void *callback_data;
25 | funnel_menu_callback_data_free callback_data_free;
26 | bool_Bool retap;
27 | } funnel_menu_t;
28 |
29 | typedef struct _console_menu {
30 | char *name;
31 | funnel_console_eval_cb_t eval_cb;
32 | funnel_console_open_cb_t open_cb;
33 | funnel_console_close_cb_t close_cb;
34 | void *user_data;
35 | funnel_console_data_free_cb_t data_free_cb;
36 | } funnel_console_menu_t;
37 |
38 | /**
39 | * Represents a single packet menu entry and callback
40 | */
41 | typedef struct _funnel_packet_menu_t {
42 | char *name; /**< Name to display in the GUI */
43 | char *required_fields; /**< comma-separated list of fields
44 | that must be present for the
45 | packet menu to be displayed */
46 | funnel_packet_menu_callback callback; /**< Lua function to be called on
47 | menu item selection. */
48 | void *callback_data; /**< Lua state for the callback
49 | function */
50 | bool_Bool retap; /**< Whether or not to rescan the
51 | capture file's packets */
52 | } funnel_packet_menu_t;
53 |
54 |
55 | /* XXX This assumes one main window and one capture file. */
56 | static const funnel_ops_t* ops;
57 | static GSList* registered_menus;
58 | static GSList* added_menus;
59 | static GSList* removed_menus;
60 | static bool_Bool menus_registered;
61 |
62 | /*
63 | * List of all registered funnel_packet_menu_t's
64 | */
65 | static GSList* registered_packet_menus;
66 | static GSList* registered_console_menus;
67 |
68 | /*
69 | * true if the packet menus were modified since the last registration
70 | */
71 | static bool_Bool packet_menus_modified;
72 |
73 | static void free_funnel_packet_menu(gpointer data, gpointer user_data);
74 |
75 | const funnel_ops_t* funnel_get_funnel_ops(void)
76 | {
77 | return ops;
78 | }
79 |
80 | static void free_funnel_menu(gpointer data, gpointer user_data _U___attribute__((unused)))
81 | {
82 | funnel_menu_t* m = (funnel_menu_t*)data;
83 |
84 | g_free(m->name);
85 | g_free(m);
9 | ← | Memory is released | →
86 | }
87 |
88 | static void funnel_remove_menu(GSList** menu_list, funnel_menu_t *menu)
89 | {
90 | GSList* current = *menu_list;
91 |
92 | while (current != NULL((void*)0)) {
2 | ← | Assuming 'current' is not equal to NULL | →
3 | ← | Loop condition is true. Entering loop body | →
93 | GSList* next = current->next; // Store the next pointer BEFORE potentially removing current
94 | funnel_menu_t* m = (funnel_menu_t*)current->data;
95 | if (m->callback == menu->callback) {
4 | ← | Assuming 'm->callback' is equal to 'menu->callback' | →
5 | ← | Taking true branch | →
96 | if (m->callback_data_free) {
6 | ← | Assuming field 'callback_data_free' is null | →
7 | ← | Taking false branch | →
97 | m->callback_data_free(m->callback_data);
98 | }
99 | free_funnel_menu(m, NULL((void*)0));
8 | ← | Calling 'free_funnel_menu' | →
10 | ← | Returning; memory was released via 1st parameter | →
100 | *menu_list = g_slist_remove(*menu_list, current->data);
11 | ← | Use of memory after it is freed
101 | }
102 |
103 | current = next; // Move to the stored next pointer
104 | }
105 | }
106 |
107 | static void funnel_clear_menu(GSList** menu_list, GFunc free_func)
108 | {
109 | g_slist_foreach(*menu_list, free_func, NULL((void*)0));
110 | g_slist_free(*menu_list);
111 |
112 | *menu_list = NULL((void*)0);
113 | }
114 |
115 | void funnel_register_menu(const char *name,
116 | register_stat_group_t group,
117 | funnel_menu_callback callback,
118 | void *callback_data,
119 | funnel_menu_callback_data_free callback_data_free,
120 | bool_Bool retap)
121 | {
122 | funnel_menu_t* m = g_new(funnel_menu_t, 1)((funnel_menu_t *) g_malloc_n ((1), sizeof (funnel_menu_t)));
123 |
124 | m->name = g_strdup(name)g_strdup_inline (name);
125 | m->group = group;
126 | m->callback = callback;
127 | m->callback_data = callback_data;
128 | m->callback_data_free = callback_data_free;
129 | m->retap = retap;
130 |
131 | registered_menus = g_slist_append(registered_menus, m);
132 |
133 | if (menus_registered) {
134 | funnel_menu_t* m_r = (funnel_menu_t *)g_memdup2(m, sizeof *m);
135 | m_r->name = g_strdup(name)g_strdup_inline (name);
136 | added_menus = g_slist_append(added_menus, m_r);
137 | }
138 | }
139 |
140 | void funnel_deregister_menus(funnel_menu_callback callback)
141 | {
142 | funnel_menu_t* m = g_new0(funnel_menu_t, 1)((funnel_menu_t *) g_malloc0_n ((1), sizeof (funnel_menu_t)));
143 |
144 | m->callback = callback;
145 |
146 | funnel_remove_menu(&registered_menus, m);
1 | Calling 'funnel_remove_menu' | →
147 | removed_menus = g_slist_append(removed_menus, m);
148 |
149 | // Clear and free memory of packet menus
150 | funnel_clear_menu(&registered_packet_menus, free_funnel_packet_menu);
151 | packet_menus_modified = true1;
152 | }
153 |
154 | static void funnel_register_all_menus(funnel_registration_cb_t r_cb)
155 | {
156 | if (r_cb == NULL((void*)0)) {
157 | return;
158 | }
159 |
160 | for (GSList* l = registered_menus; l; l = l->next) {
161 | funnel_menu_t* c = (funnel_menu_t*)l->data;
162 | r_cb(c->name,c->group,c->callback,c->callback_data,c->retap);
163 | }
164 | }
165 |
166 | void funnel_reload_menus(funnel_deregistration_cb_t d_cb,
167 | funnel_registration_cb_t r_cb)
168 | {
169 | for (GSList* l = removed_menus; l; l = l->next) {
170 | funnel_menu_t* c = (funnel_menu_t*)l->data;
171 | d_cb(c->callback);
172 | }
173 |
174 | for (GSList* l = added_menus; l; l = l->next) {
175 | funnel_menu_t* c = (funnel_menu_t*)l->data;
176 | r_cb(c->name,c->group,c->callback,c->callback_data,c->retap);
177 | }
178 |
179 | funnel_clear_menu(&removed_menus, free_funnel_menu);
180 | funnel_clear_menu(&added_menus, free_funnel_menu);
181 | }
182 |
183 | /**
184 | * Entry point for Lua code to register a packet menu
185 | *
186 | * Stores the menu name and callback from the Lua code
187 | * into registered_packet_menus so that the
188 | * Wireshark GUI code can retrieve it with
189 | * funnel_register_all_packet_menus().
190 | */
191 | void funnel_register_packet_menu(const char *name,
192 | const char *required_fields,
193 | funnel_packet_menu_callback callback,
194 | void *callback_data,
195 | bool_Bool retap)
196 | {
197 | funnel_packet_menu_t* m = g_new0(funnel_packet_menu_t, 1)((funnel_packet_menu_t *) g_malloc0_n ((1), sizeof (funnel_packet_menu_t )));
198 |
199 | m->name = g_strdup(name)g_strdup_inline (name);
200 | m->required_fields = g_strdup(required_fields)g_strdup_inline (required_fields);
201 | m->callback = callback;
202 | m->callback_data = callback_data;
203 | m->retap = retap;
204 |
205 | registered_packet_menus = g_slist_append(registered_packet_menus, m);
206 |
207 | packet_menus_modified = true1;
208 | }
209 |
210 | static void free_funnel_packet_menu(gpointer data, gpointer user_data _U___attribute__((unused)))
211 | {
212 | funnel_packet_menu_t* m = (funnel_packet_menu_t*)data;
213 |
214 | g_free(m->name);
215 | g_free(m->required_fields);
216 | if (m->callback_data) {
217 | g_free(m->callback_data);
218 | }
219 | g_free(m);
220 | }
221 |
222 | /**
223 | * Entry point for Wireshark GUI to obtain all registered packet menus
224 | *
225 | * Calls the supplied callback for each packet menu registered with
226 | * funnel_register_packet_menu().
227 | *
228 | * @param r_cb the callback function to call with each registered packet menu
229 | */
230 | void funnel_register_all_packet_menus(funnel_registration_packet_cb_t r_cb)
231 | {
232 | for (GSList* l = registered_packet_menus; l; l = l->next) {
233 | funnel_packet_menu_t* c = (funnel_packet_menu_t*)l->data;
234 | r_cb(c->name, c->required_fields, c->callback, c->callback_data, c->retap);
235 | }
236 |
237 | packet_menus_modified = false0;
238 | }
239 |
240 | /**
241 | * Returns whether the packet menus have been modified since they were last registered
242 | *
243 | * @return true if the packet menus were modified since the last registration
244 | */
245 | bool_Bool funnel_packet_menus_modified(void)
246 | {
247 | return packet_menus_modified;
248 | }
249 |
250 | /**
251 | * Entry point for code to register a console menu
252 | */
253 | void funnel_register_console_menu(const char *name,
254 | funnel_console_eval_cb_t eval_cb,
255 | funnel_console_open_cb_t open_cb,
256 | funnel_console_close_cb_t close_cb,
257 | void *callback_data,
258 | funnel_console_data_free_cb_t free_data)
259 | {
260 | funnel_console_menu_t* m = g_new0(funnel_console_menu_t, 1)((funnel_console_menu_t *) g_malloc0_n ((1), sizeof (funnel_console_menu_t )));
261 |
262 | m->name = g_strdup(name)g_strdup_inline (name);
263 | m->eval_cb = eval_cb;
264 | m->open_cb = open_cb;
265 | m->close_cb = close_cb;
266 | m->user_data = callback_data;
267 | m->data_free_cb = free_data;
268 |
269 | registered_console_menus = g_slist_prepend(registered_console_menus, m);
270 | }
271 |
272 | static void funnel_register_all_console_menus(funnel_registration_console_cb_t r_cb)
273 | {
274 | if (r_cb == NULL((void*)0)) {
275 | return;
276 | }
277 |
278 | for (GSList* l = registered_console_menus; l != NULL((void*)0); l = l->next) {
279 | funnel_console_menu_t *m = l->data;
280 | r_cb(m->name, m->eval_cb, m->open_cb, m->close_cb, m->user_data);
281 | }
282 | }
283 |
284 | static void free_funnel_console_menu(gpointer data, gpointer user_data _U___attribute__((unused)))
285 | {
286 | funnel_console_menu_t* m = data;
287 |
288 | g_free(m->name);
289 | if (m->data_free_cb) {
290 | m->data_free_cb(m->user_data);
291 | }
292 | g_free(m);
293 | }
294 |
295 | void funnel_ops_init(const funnel_ops_t* o, funnel_registration_cb_t r_cb, funnel_registration_console_cb_t rconsole_cb)
296 | {
297 | ops = o;
298 | funnel_register_all_menus(r_cb);
299 | funnel_register_all_console_menus(rconsole_cb);
300 | menus_registered = true1;
301 | }
302 |
303 | bool_Bool funnel_menu_registered(void)
304 | {
305 | return menus_registered;
306 | }
307 |
308 | void funnel_cleanup(void)
309 | {
310 | funnel_clear_menu(&registered_menus, free_funnel_menu);
311 | funnel_clear_menu(&registered_packet_menus, free_funnel_packet_menu);
312 | funnel_clear_menu(&registered_console_menus, free_funnel_console_menu);
313 | }
314 |
315 | /*
316 | * Editor modelines - https://www.wireshark.org/tools/modelines.html
317 | *
318 | * Local variables:
319 | * c-basic-offset: 4
320 | * tab-width: 8
321 | * indent-tabs-mode: nil
322 | * End:
323 | *
324 | * vi: set shiftwidth=4 tabstop=8 expandtab:
325 | * :indentSize=4:tabSize=8:noTabs=true:
326 | */