extcap: Fix misc memory leaks triggered by network interface changes

Valgrind reports plenty of misc memory leaks in extcap after the network
interface list has changed or is refreshed. Errors can be seen by
starting Wireshark with Valgrind's memcheck tool and bringing a network
interface up and down a few times with:

ifconfig eth0 up
ifconfig eth0 down

Change-Id: I90f53847071854b7d02facb39b7a380732de79b4
Reviewed-on: https://code.wireshark.org/review/17606
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
This commit is contained in:
Mikael Kanstrup 2016-09-08 14:26:58 +02:00 committed by Peter Wu
parent e079862fad
commit c64762d33c
5 changed files with 86 additions and 35 deletions

View File

@ -119,11 +119,14 @@ extcap_if_executable(const gchar *ifname)
return interface != NULL ? interface->extcap_path : NULL; return interface != NULL ? interface->extcap_path : NULL;
} }
static void static gboolean
extcap_if_add(extcap_interface * interface) extcap_if_add(extcap_interface * interface)
{ {
if (!g_hash_table_lookup(ifaces, interface->call)) if (g_hash_table_lookup(ifaces, interface->call))
g_hash_table_insert(ifaces, g_strdup(interface->call), interface); return FALSE;
g_hash_table_insert(ifaces, g_strdup(interface->call), interface);
return TRUE;
} }
static void static void
@ -202,6 +205,12 @@ static void extcap_free_dlt(gpointer d, gpointer user_data _U_) {
g_free(((extcap_dlt *)d)->name); g_free(((extcap_dlt *)d)->name);
g_free(((extcap_dlt *)d)->display); g_free(((extcap_dlt *)d)->display);
g_free(d);
}
static void extcap_free_dlts(GList * dlts) {
g_list_foreach(dlts, extcap_free_dlt, NULL);
g_list_free(dlts);
} }
static gboolean dlt_cb(const gchar *extcap _U_, const gchar *ifname _U_, gchar *output, void *data, static gboolean dlt_cb(const gchar *extcap _U_, const gchar *ifname _U_, gchar *output, void *data,
@ -253,7 +262,7 @@ static gboolean dlt_cb(const gchar *extcap _U_, const gchar *ifname _U_, gchar *
g_free(caps); g_free(caps);
} }
g_list_foreach(temp, extcap_free_dlt, NULL); extcap_free_dlts(temp);
return FALSE; return FALSE;
} }
@ -293,12 +302,22 @@ static void extcap_free_interface(gpointer i) {
g_free(interface->display); g_free(interface->display);
g_free(interface->version); g_free(interface->version);
g_free(interface->help); g_free(interface->help);
g_free(interface->extcap_path);
g_free(interface);
}
static void extcap_free_interfaces(GList * interfaces) {
if (interfaces == NULL)
return;
g_list_foreach(interfaces, (GFunc)extcap_free_interface, NULL);
g_list_free(interfaces);
} }
static gboolean interfaces_cb(const gchar *extcap, const gchar *ifname _U_, gchar *output, void *data, static gboolean interfaces_cb(const gchar *extcap, const gchar *ifname _U_, gchar *output, void *data,
char **err_str _U_) { char **err_str _U_) {
GList **il = (GList **) data; GList **il = (GList **) data;
GList *interfaces = NULL, *walker = NULL; GList *interfaces = NULL, *walker = NULL, *tmp = NULL;
extcap_interface *int_iter = NULL; extcap_interface *int_iter = NULL;
if_info_t *if_info = NULL; if_info_t *if_info = NULL;
@ -308,6 +327,9 @@ static gboolean interfaces_cb(const gchar *extcap, const gchar *ifname _U_, gcha
walker = interfaces; walker = interfaces;
while (walker != NULL ) { while (walker != NULL ) {
/* Whether the interface information needs to be preserved or not. */
gboolean preserve_interface = FALSE;
int_iter = (extcap_interface *)walker->data; int_iter = (extcap_interface *)walker->data;
if ( int_iter->if_type == EXTCAP_SENTENCE_INTERFACE && extcap_if_exists(int_iter->call) ) if ( int_iter->if_type == EXTCAP_SENTENCE_INTERFACE && extcap_if_exists(int_iter->call) )
{ {
@ -336,15 +358,23 @@ static gboolean interfaces_cb(const gchar *extcap, const gchar *ifname _U_, gcha
} }
int_iter->extcap_path = g_strdup(extcap); int_iter->extcap_path = g_strdup(extcap);
extcap_if_add(int_iter); preserve_interface = extcap_if_add(int_iter);
} }
/* Call for interfaces and tools alike. Multiple calls (because a tool has multiple /* Call for interfaces and tools alike. Multiple calls (because a tool has multiple
* interfaces) are handled internally */ * interfaces) are handled internally */
extcap_tool_add(extcap, int_iter); extcap_tool_add(extcap, int_iter);
tmp = walker;
walker = g_list_next(walker); walker = g_list_next(walker);
/* If interface was added to ifaces hash list then the hash list will free
* the resources. Remove the interface from interfaces list so it won't be
* freed when exiting this function */
if (preserve_interface)
interfaces = g_list_delete_link(interfaces, tmp);
} }
extcap_free_interfaces(interfaces);
return TRUE; return TRUE;
} }
@ -425,11 +455,6 @@ append_extcap_interface_list(GList *list, char **err_str) {
return list; return list;
} }
static void extcap_free_arg_elem(gpointer data, gpointer user_data _U_) {
extcap_free_arg((extcap_arg *) data);
g_free(data);
}
void extcap_register_preferences(void) void extcap_register_preferences(void)
{ {
GList * interfaces = NULL; GList * interfaces = NULL;
@ -497,17 +522,18 @@ static gchar ** extcap_prefs_dynamic_valptr(const char *name)
return valp; return valp;
} }
static void extcap_free_if_configuration(GList *list) void extcap_free_if_configuration(GList *list, gboolean free_args)
{ {
GList *elem, *sl; GList *elem, *sl;
for (elem = g_list_first(list); elem; elem = elem->next) for (elem = g_list_first(list); elem; elem = elem->next)
{ {
if (elem->data != NULL) { if (elem->data != NULL) {
/* g_list_free_full() only exists since 2.28. */
sl = g_list_first((GList *)elem->data); sl = g_list_first((GList *)elem->data);
g_list_foreach(sl, (GFunc)extcap_free_arg_elem, NULL); if (free_args)
g_list_free(sl); extcap_free_arg_list(sl);
else
g_list_free(sl);
} }
} }
g_list_free(list); g_list_free(list);
@ -692,7 +718,7 @@ extcap_has_configuration(const char * ifname, gboolean is_required) {
} }
walker = walker->next; walker = walker->next;
} }
extcap_free_if_configuration(arguments); extcap_free_if_configuration(arguments, TRUE);
return found; return found;
} }
@ -988,7 +1014,7 @@ GPtrArray * extcap_prepare_arguments(interface_options interface_opts)
} }
} }
extcap_free_if_configuration(arglist); extcap_free_if_configuration(arglist, TRUE);
} }
else else
{ {

View File

@ -88,6 +88,15 @@ extcap_tools_list(void);
GList * GList *
extcap_get_if_configuration(const char * ifname); extcap_get_if_configuration(const char * ifname);
/**
* Frees the memory from extcap_get_if_configuration.
* @param list The list returned by extcap_get_if_configuration.
* @param free_args TRUE if all arguments in the list must be freed too or FALSE
* if the ownership of the arguments is taken by the caller.
*/
void
extcap_free_if_configuration(GList *list, gboolean free_args);
gboolean gboolean
extcap_has_configuration(const char * ifname, gboolean is_required); extcap_has_configuration(const char * ifname, gboolean is_required);

View File

@ -118,7 +118,6 @@ static extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) {
extcap_token_sentence *rs = g_new0(extcap_token_sentence, 1); extcap_token_sentence *rs = g_new0(extcap_token_sentence, 1);
rs->sentence = NULL; rs->sentence = NULL;
rs->param_list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
/* Regex for catching just the allowed values for sentences */ /* Regex for catching just the allowed values for sentences */
if ( ( regex = g_regex_new ( "^[\\t| ]*(arg|value|interface|extcap|dlt)(?=[\\t| ]+\\{)", if ( ( regex = g_regex_new ( "^[\\t| ]*(arg|value|interface|extcap|dlt)(?=[\\t| ]+\\{)",
@ -137,6 +136,8 @@ static extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) {
return NULL; return NULL;
} }
rs->param_list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
/* Capture the argument and the value of the list. This will ensure, /* Capture the argument and the value of the list. This will ensure,
* that regex patterns given to {validation=} are parsed correctly, * that regex patterns given to {validation=} are parsed correctly,
* as long as }{ does not occur within the pattern */ * as long as }{ does not occur within the pattern */
@ -150,7 +151,7 @@ static extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) {
if ( arg == NULL ) if ( arg == NULL )
break; break;
param_value = g_strdup(g_match_info_fetch ( match_info, 2 )); param_value = g_match_info_fetch ( match_info, 2 );
if (g_ascii_strcasecmp(arg, "number") == 0) { if (g_ascii_strcasecmp(arg, "number") == 0) {
param_type = EXTCAP_PARAM_ARGNUM; param_type = EXTCAP_PARAM_ARGNUM;
@ -197,6 +198,7 @@ static extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) {
g_hash_table_insert(rs->param_list, ENUM_KEY(param_type), param_value); g_hash_table_insert(rs->param_list, ENUM_KEY(param_type), param_value);
g_match_info_next(match_info, &error); g_match_info_next(match_info, &error);
g_free(arg);
} }
g_match_info_free(match_info); g_match_info_free(match_info);
g_regex_unref(regex); g_regex_unref(regex);
@ -260,15 +262,12 @@ void extcap_free_arg(extcap_arg *a) {
extcap_free_complex(a->default_complex); extcap_free_complex(a->default_complex);
g_list_foreach(a->values, (GFunc) extcap_free_valuelist, NULL); g_list_foreach(a->values, (GFunc) extcap_free_valuelist, NULL);
} g_list_free(a->values);
g_free(a);
static void extcap_free_arg_list_cb(gpointer listentry, gpointer data _U_) {
if (listentry != NULL)
extcap_free_arg((extcap_arg *) listentry);
} }
void extcap_free_arg_list(GList *a) { void extcap_free_arg_list(GList *a) {
g_list_foreach(a, extcap_free_arg_list_cb, NULL); g_list_foreach(a, (GFunc)extcap_free_arg, NULL);
g_list_free(a); g_list_free(a);
} }
@ -279,12 +278,22 @@ static gint glist_find_numbered_arg(gconstpointer listelem, gconstpointer needle
} }
static void extcap_free_tokenized_sentence(gpointer s, gpointer user_data _U_) { static void extcap_free_tokenized_sentence(gpointer s, gpointer user_data _U_) {
extcap_token_sentence *t = (extcap_token_sentence *)s;
if (s == NULL) if (t == NULL)
return; return;
g_free(((extcap_token_sentence *)s)->sentence); g_free(t->sentence);
g_hash_table_destroy(((extcap_token_sentence *)s)->param_list); g_hash_table_destroy(t->param_list);
g_free(t);
}
static void extcap_free_tokenized_sentences(GList *sentences) {
if (sentences == NULL)
return;
g_list_foreach(sentences, extcap_free_tokenized_sentence, NULL);
g_list_free(sentences);
} }
static extcap_arg *extcap_parse_arg_sentence(GList * args, extcap_token_sentence *s) { static extcap_arg *extcap_parse_arg_sentence(GList * args, extcap_token_sentence *s) {
@ -530,7 +539,7 @@ GList * extcap_parse_args(gchar *output) {
walker = g_list_next(walker); walker = g_list_next(walker);
} }
g_list_foreach(temp, extcap_free_tokenized_sentence, NULL); extcap_free_tokenized_sentences(temp);
return result; return result;
} }
@ -603,7 +612,7 @@ GList * extcap_parse_interfaces(gchar *output) {
walker = g_list_next(walker); walker = g_list_next(walker);
} }
g_list_foreach(tokens, extcap_free_tokenized_sentence, NULL); extcap_free_tokenized_sentences(tokens);
return result; return result;
} }
@ -681,7 +690,7 @@ GList * extcap_parse_dlts(gchar *output) {
walker = g_list_next(walker); walker = g_list_next(walker);
} }
g_list_foreach(temp, extcap_free_tokenized_sentence, NULL); extcap_free_tokenized_sentences(temp);
return result; return result;
} }

View File

@ -122,6 +122,7 @@ gboolean extcap_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar
if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0)) if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
{ {
g_free(argv[0]);
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle"); g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
return FALSE; return FALSE;
} }
@ -130,6 +131,7 @@ gboolean extcap_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar
{ {
CloseHandle(child_stdout_rd); CloseHandle(child_stdout_rd);
CloseHandle(child_stdout_wr); CloseHandle(child_stdout_wr);
g_free(argv[0]);
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle"); g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
return FALSE; return FALSE;
} }
@ -192,6 +194,7 @@ gboolean extcap_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar
} }
g_free(local_output); g_free(local_output);
g_free(argv[0]);
g_free(argv); g_free(argv);
return result; return result;

View File

@ -194,7 +194,7 @@ void ExtcapOptionsDialog::anyValueChanged()
void ExtcapOptionsDialog::loadArguments() void ExtcapOptionsDialog::loadArguments()
{ {
GList * arguments = NULL, * item = NULL; GList * arguments = NULL, * walker = NULL, * item = NULL;
ExtcapArgument * argument = NULL; ExtcapArgument * argument = NULL;
if ( device_name.length() == 0 ) if ( device_name.length() == 0 )
@ -207,9 +207,10 @@ void ExtcapOptionsDialog::loadArguments()
ExtcapArgumentList required; ExtcapArgumentList required;
ExtcapArgumentList optional; ExtcapArgumentList optional;
while ( arguments != NULL ) walker = arguments;
while ( walker != NULL )
{ {
item = g_list_first((GList *)(arguments->data)); item = g_list_first((GList *)(walker->data));
while ( item != NULL ) while ( item != NULL )
{ {
argument = ExtcapArgument::create((extcap_arg *)(item->data)); argument = ExtcapArgument::create((extcap_arg *)(item->data));
@ -223,7 +224,7 @@ void ExtcapOptionsDialog::loadArguments()
} }
item = item->next; item = item->next;
} }
arguments = g_list_next(arguments); walker = g_list_next(walker);
} }
if ( required.length() > 0 ) if ( required.length() > 0 )
@ -231,6 +232,9 @@ void ExtcapOptionsDialog::loadArguments()
if ( optional.length() > 0 ) if ( optional.length() > 0 )
extcapArguments << optional; extcapArguments << optional;
/* argument items are now owned by ExtcapArgument. Only free the lists */
extcap_free_if_configuration(arguments, FALSE);
} }
void ExtcapOptionsDialog::updateWidgets() void ExtcapOptionsDialog::updateWidgets()