Bug Summary

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

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