diff options
author | Stig Bjørlykke <stig@bjorlykke.org> | 2015-08-11 14:08:08 +0200 |
---|---|---|
committer | Stig Bjørlykke <stig@bjorlykke.org> | 2015-08-11 12:09:07 +0000 |
commit | ecc4f756bdb6175cc0b3b11af2f90884db1c602c (patch) | |
tree | 99d8ca48a72752e1257d4b8b321f41d1767ee020 /epan | |
parent | 70d06deb2e31bd605e672200a7755764febe94ae (diff) |
Added Reload Lua plugins.
This is initial support for reloading Lua plugins without
restarting the application.
Still todo:
- Deregister FileHandlers
- Support deregister ProtoField with existing abbrev (same_name_hfinfo)
- Add a progress dialog when reloading many plugins
- Search for memory leakages in wslua functions
Change-Id: I48870d8741251705ca15ffe1068613fcb0cb18c1
Reviewed-on: https://code.wireshark.org/review/5028
Reviewed-by: Stig Bjørlykke <stig@bjorlykke.org>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-http.c | 4 | ||||
-rw-r--r-- | epan/dissectors/packet-imf.c | 4 | ||||
-rw-r--r-- | epan/dissectors/packet-ldap.c | 4 | ||||
-rw-r--r-- | epan/expert.c | 5 | ||||
-rw-r--r-- | epan/expert.h | 5 | ||||
-rw-r--r-- | epan/funnel.c | 102 | ||||
-rw-r--r-- | epan/funnel.h | 11 | ||||
-rw-r--r-- | epan/packet.c | 70 | ||||
-rw-r--r-- | epan/packet.h | 19 | ||||
-rw-r--r-- | epan/prefs.c | 31 | ||||
-rw-r--r-- | epan/prefs.h | 5 | ||||
-rw-r--r-- | epan/proto.c | 47 | ||||
-rw-r--r-- | epan/proto.h | 12 | ||||
-rw-r--r-- | epan/wmem/wmem_tree.c | 16 | ||||
-rw-r--r-- | epan/wmem/wmem_tree.h | 7 | ||||
-rw-r--r-- | epan/wslua/init_wslua.c | 101 | ||||
-rw-r--r-- | epan/wslua/init_wslua.h | 2 | ||||
-rw-r--r-- | epan/wslua/wslua.h | 17 | ||||
-rw-r--r-- | epan/wslua/wslua_dissector.c | 44 | ||||
-rw-r--r-- | epan/wslua/wslua_field.c | 6 | ||||
-rw-r--r-- | epan/wslua/wslua_file_handler.c | 5 | ||||
-rw-r--r-- | epan/wslua/wslua_gui.c | 21 | ||||
-rw-r--r-- | epan/wslua/wslua_listener.c | 49 | ||||
-rw-r--r-- | epan/wslua/wslua_pref.c | 8 | ||||
-rw-r--r-- | epan/wslua/wslua_proto.c | 110 | ||||
-rw-r--r-- | epan/wslua/wslua_proto_expert.c | 16 | ||||
-rw-r--r-- | epan/wslua/wslua_proto_field.c | 33 | ||||
-rw-r--r-- | epan/wslua/wslua_tree.c | 1 |
28 files changed, 635 insertions, 120 deletions
diff --git a/epan/dissectors/packet-http.c b/epan/dissectors/packet-http.c index e47fb13891..00e5e85a0a 100644 --- a/epan/dissectors/packet-http.c +++ b/epan/dissectors/packet-http.c @@ -2354,9 +2354,9 @@ header_fields_initialize_cb(void) if (header_fields_hash && hf) { guint hf_size = g_hash_table_size (header_fields_hash); - /* Unregister all fields */ + /* Deregister all fields */ for (i = 0; i < hf_size; i++) { - proto_unregister_field (proto_http, *(hf[i].p_id)); + proto_deregister_field (proto_http, *(hf[i].p_id)); g_free (hf[i].p_id); } g_hash_table_destroy (header_fields_hash); diff --git a/epan/dissectors/packet-imf.c b/epan/dissectors/packet-imf.c index 942ab19068..be1fdba95a 100644 --- a/epan/dissectors/packet-imf.c +++ b/epan/dissectors/packet-imf.c @@ -872,9 +872,9 @@ header_fields_initialize_cb (void) if (custom_field_table && hf) { guint hf_size = g_hash_table_size (custom_field_table); - /* Unregister all fields */ + /* Deregister all fields */ for (i = 0; i < hf_size; i++) { - proto_unregister_field (proto_imf, *(hf[i].p_id)); + proto_deregister_field (proto_imf, *(hf[i].p_id)); g_free (hf[i].p_id); } g_hash_table_destroy (custom_field_table); diff --git a/epan/dissectors/packet-ldap.c b/epan/dissectors/packet-ldap.c index d415971c12..8b247f8743 100644 --- a/epan/dissectors/packet-ldap.c +++ b/epan/dissectors/packet-ldap.c @@ -771,9 +771,9 @@ attribute_types_initialize_cb(void) if (attribute_types_hash && hf) { guint hf_size = g_hash_table_size (attribute_types_hash); - /* Unregister all fields */ + /* Deregister all fields */ for (i = 0; i < hf_size; i++) { - proto_unregister_field (proto_ldap, *(hf[i].p_id)); + proto_deregister_field (proto_ldap, *(hf[i].p_id)); g_free (hf[i].p_id); } g_hash_table_destroy (attribute_types_hash); diff --git a/epan/expert.c b/epan/expert.c index c54b5e18df..fe6943caa1 100644 --- a/epan/expert.c +++ b/epan/expert.c @@ -322,6 +322,11 @@ expert_module_t *expert_register_protocol(int id) return module; } +void expert_deregister_protocol (expert_module_t *module) +{ + wmem_free(wmem_epan_scope(), module); +} + static int expert_register_field_init(expert_field_info *expinfo, expert_module_t *module) { diff --git a/epan/expert.h b/epan/expert.h index dc994ba4fc..e1d9ff9106 100644 --- a/epan/expert.h +++ b/epan/expert.h @@ -171,6 +171,11 @@ proto_tree_add_expert_format(proto_tree *tree, packet_info *pinfo, expert_field */ WS_DLL_PUBLIC expert_module_t *expert_register_protocol(int id); +/** + * Deregister expert info from a protocol. + */ +WS_DLL_PUBLIC void expert_deregister_protocol (expert_module_t *module); + /** Register a expert field array. @param module the protocol handle from expert_register_protocol() @param ei the ei_register_info array diff --git a/epan/funnel.c b/epan/funnel.c index 02cd4f1171..fd1f8612bd 100644 --- a/epan/funnel.c +++ b/epan/funnel.c @@ -31,7 +31,7 @@ typedef struct _funnel_menu_t { const char *name; register_stat_group_t group; - void (*callback)(gpointer); + funnel_menu_callback callback; gpointer callback_data; gboolean retap; struct _funnel_menu_t* next; @@ -39,16 +39,69 @@ typedef struct _funnel_menu_t { /* XXX This assumes one main window and one capture file. */ static const funnel_ops_t* ops = NULL; -static funnel_menu_t* menus = NULL; +static funnel_menu_t* registered_menus = NULL; +static funnel_menu_t* added_menus = NULL; +static funnel_menu_t* removed_menus = NULL; +static gboolean menus_registered = FALSE; const funnel_ops_t* funnel_get_funnel_ops(void) { return ops; } void funnel_set_funnel_ops(const funnel_ops_t* o) { ops = o; } +static void funnel_insert_menu (funnel_menu_t** menu_list, funnel_menu_t *menu) +{ + if (!(*menu_list)) { + *menu_list = menu; + } else { + funnel_menu_t* c; + for (c = *menu_list; c->next; c = c->next); + c->next = menu; + } +} + +static void funnel_remove_menu (funnel_menu_t ** menu_list, funnel_menu_t *menu) +{ + funnel_menu_t *m = *menu_list, *p = NULL; + + while (m) { + if (m->callback == menu->callback) { + if (p) { + p->next = m->next; + } else { + *menu_list = m->next; + } + g_free((char *)m->name); + g_free(m); + if (p) { + m = p->next; + } else { + m = *menu_list ? (*menu_list)->next : NULL; + } + } else { + p = m; + m = m->next; + } + } +} + +static void funnel_clear_menu (funnel_menu_t** menu_list) +{ + funnel_menu_t *m; + + while (*menu_list) { + m = *menu_list; + *menu_list = m->next; + g_free((char *)m->name); + g_free(m); + } + *menu_list = NULL; +} + void funnel_register_menu(const char *name, register_stat_group_t group, - void (*callback)(gpointer), + funnel_menu_callback callback, gpointer callback_data, - gboolean retap) { + gboolean retap) +{ funnel_menu_t* m = (funnel_menu_t *)g_malloc(sizeof(funnel_menu_t)); m->name = g_strdup(name); m->group = group; @@ -57,20 +110,45 @@ void funnel_register_menu(const char *name, m->retap = retap; m->next = NULL; - if (!menus) { - menus = m; - } else { - funnel_menu_t* c; - for (c = menus; c->next; c = c->next); - c->next = m; + funnel_insert_menu(®istered_menus, m); + if (menus_registered) { + funnel_menu_t* m_r = (funnel_menu_t *)g_memdup(m, sizeof *m); + m_r->name = g_strdup(name); + funnel_insert_menu(&added_menus, m_r); } } -void funnel_register_all_menus(funnel_registration_cb_t r_cb) { +void funnel_deregister_menus(funnel_menu_callback callback) +{ + funnel_menu_t* m = (funnel_menu_t *)g_malloc0(sizeof(funnel_menu_t)); + m->callback = callback; + + funnel_remove_menu(®istered_menus, m); + funnel_insert_menu(&removed_menus, m); +} + +void funnel_register_all_menus(funnel_registration_cb_t r_cb) +{ funnel_menu_t* c; - for (c = menus; c; c = c->next) { + for (c = registered_menus; c; c = c->next) { r_cb(c->name,c->group,c->callback,c->callback_data,c->retap); } + menus_registered = TRUE; +} + +void funnel_reload_menus(funnel_deregistration_cb_t d_cb, + funnel_registration_cb_t r_cb) +{ + funnel_menu_t* c; + for (c = removed_menus; c; c = c->next) { + d_cb(c->callback); + } + for (c = added_menus; c; c = c->next) { + r_cb(c->name,c->group,c->callback,c->callback_data,c->retap); + } + + funnel_clear_menu(&removed_menus); + funnel_clear_menu(&added_menus); } /* diff --git a/epan/funnel.h b/epan/funnel.h index b7e2ac1d01..d7d00020e4 100644 --- a/epan/funnel.h +++ b/epan/funnel.h @@ -46,6 +46,8 @@ typedef void (*funnel_dlg_cb_t)(gchar** user_input, void* data); typedef gboolean (*funnel_bt_cb_t)(funnel_text_window_t* tw, void* data); +typedef void (* funnel_menu_callback)(gpointer); + typedef struct _funnel_bt_t { funnel_text_window_t* tw; funnel_bt_cb_t func; @@ -74,6 +76,7 @@ typedef struct _funnel_ops_t { funnel_dlg_cb_t dlg_cb, void* data); + void (*close_dialogs)(void); void (*logger)(const gchar *log_domain, GLogLevelFlags log_level, @@ -104,17 +107,21 @@ WS_DLL_PUBLIC void funnel_set_funnel_ops(const funnel_ops_t*); WS_DLL_PUBLIC void funnel_register_menu(const char *name, register_stat_group_t group, - void (*callback)(gpointer), + funnel_menu_callback callback, gpointer callback_data, gboolean retap); +WS_DLL_PUBLIC void funnel_deregister_menus(void (*callback)(gpointer)); typedef void (*funnel_registration_cb_t)(const char *name, register_stat_group_t group, - void (*callback)(gpointer), + funnel_menu_callback callback, gpointer callback_data, gboolean retap); +typedef void (*funnel_deregistration_cb_t)(funnel_menu_callback callback); WS_DLL_PUBLIC void funnel_register_all_menus(funnel_registration_cb_t r_cb); +WS_DLL_PUBLIC void funnel_reload_menus(funnel_deregistration_cb_t d_cb, + funnel_registration_cb_t r_cb); extern void initialize_funnel_ops(void); diff --git a/epan/packet.c b/epan/packet.c index 61547aef1e..40d005acdc 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -1021,6 +1021,14 @@ dissector_delete_all_check (gpointer key _U_, gpointer value, gpointer user_data dtbl_entry_t *dtbl_entry = (dtbl_entry_t *) value; dissector_handle_t handle = (dissector_handle_t) user_data; + if (!dtbl_entry->current->protocol) { + /* + * Not all dissectors are registered with a protocol, so we need this + * check when running from dissector_delete_from_all_tables. + */ + return FALSE; + } + return (proto_get_id (dtbl_entry->current->protocol) == proto_get_id (handle->protocol)); } @@ -1033,6 +1041,23 @@ void dissector_delete_all(const char *name, dissector_handle_t handle) g_hash_table_foreach_remove (sub_dissectors->hash_table, dissector_delete_all_check, handle); } +static void +dissector_delete_from_table(gpointer key _U_, gpointer value, gpointer user_data) +{ + dissector_table_t sub_dissectors = (dissector_table_t) value; + g_assert (sub_dissectors); + + g_hash_table_foreach_remove(sub_dissectors->hash_table, dissector_delete_all_check, user_data); + sub_dissectors->dissector_handles = g_slist_remove(sub_dissectors->dissector_handles, user_data); +} + +/* Delete handle from all tables and dissector_handles lists */ +static void +dissector_delete_from_all_tables(dissector_handle_t handle) +{ + g_hash_table_foreach(dissector_tables, dissector_delete_from_table, handle); +} + /* Change the entry for a dissector in a uint dissector table with a particular pattern to use a new dissector handle. */ void @@ -1927,6 +1952,15 @@ dissector_table_t register_custom_dissector_table(const char *name, return sub_dissectors; } +void +deregister_dissector_table(const char *name) +{ + dissector_table_t sub_dissectors = find_dissector_table(name); + if (!sub_dissectors) return; + + g_hash_table_remove(dissector_tables, (gpointer)name); +} + const char * get_dissector_table_ui_name(const char *name) { @@ -2428,6 +2462,7 @@ create_dissector_handle(dissector_t dissector, const int proto) return handle; } +/* Create an anonymous handle for a new dissector. */ dissector_handle_t new_create_dissector_handle(new_dissector_t dissector, const int proto) { @@ -2456,6 +2491,17 @@ dissector_handle_t new_create_dissector_handle_with_name(new_dissector_t dissect return handle; } +/* Destroy an anonymous handle for a dissector. */ +void +destroy_dissector_handle(dissector_handle_t handle) +{ + if (handle == NULL) return; + + dissector_delete_from_all_tables(handle); + deregister_postdissector(handle); + wmem_free(wmem_epan_scope(), handle); +} + /* Register a dissector by name. */ dissector_handle_t register_dissector(const char *name, dissector_t dissector, const int proto) @@ -2477,6 +2523,7 @@ register_dissector(const char *name, dissector_t dissector, const int proto) return handle; } +/* Register a new dissector by name. */ dissector_handle_t new_register_dissector(const char *name, new_dissector_t dissector, const int proto) { @@ -2497,6 +2544,19 @@ new_register_dissector(const char *name, new_dissector_t dissector, const int pr return handle; } +/* Deregister a dissector by name. */ +void +deregister_dissector(const char *name) +{ + dissector_handle_t handle = find_dissector(name); + if (handle == NULL) return; + + g_hash_table_remove(registered_dissectors, (gpointer)name); + g_hash_table_remove(heur_dissector_lists, (gpointer)name); + + destroy_dissector_handle(handle); +} + /* Call a dissector through a handle but if the dissector rejected it * return 0. */ @@ -2743,6 +2803,16 @@ register_postdissector(dissector_handle_t handle) num_of_postdissectors++; } +void +deregister_postdissector(dissector_handle_t handle) +{ + if (!post_dissectors) return; + + if (g_ptr_array_remove(post_dissectors, handle)) { + num_of_postdissectors--; + } +} + gboolean have_postdissector(void) { diff --git a/epan/packet.h b/epan/packet.h index b2dfe43986..cd81bc2ddb 100644 --- a/epan/packet.h +++ b/epan/packet.h @@ -213,6 +213,9 @@ WS_DLL_PUBLIC dissector_table_t register_dissector_table(const char *name, WS_DLL_PUBLIC dissector_table_t register_custom_dissector_table(const char *name, const char *ui_name, GHashFunc hash_func, GEqualFunc key_equal_func); +/** Deregister the dissector table by table name. */ +WS_DLL_PUBLIC void deregister_dissector_table(const char *name); + /* Find a dissector table by table name. */ WS_DLL_PUBLIC dissector_table_t find_dissector_table(const char *name); @@ -484,10 +487,13 @@ WS_DLL_PUBLIC void heur_dissector_delete(const char *name, heur_dissector_t diss extern void heur_dissector_set_enabled(const char *name, heur_dissector_t dissector, const int proto, const gboolean enabled); /** Register a dissector. */ -WS_DLL_PUBLIC dissector_handle_t register_dissector(const char *name, dissector_t dissector, - const int proto); -WS_DLL_PUBLIC dissector_handle_t new_register_dissector(const char *name, new_dissector_t dissector, - const int proto); +WS_DLL_PUBLIC dissector_handle_t register_dissector(const char *name, dissector_t dissector, const int proto); + +/** Register a new dissector. */ +WS_DLL_PUBLIC dissector_handle_t new_register_dissector(const char *name, new_dissector_t dissector, const int proto); + +/** Deregister a dissector. */ +WS_DLL_PUBLIC void deregister_dissector(const char *name); /** Get the long name of the protocol for a dissector handle. */ extern const char *dissector_handle_get_long_name(const dissector_handle_t handle); @@ -515,6 +521,9 @@ WS_DLL_PUBLIC dissector_handle_t new_create_dissector_handle(new_dissector_t dis WS_DLL_PUBLIC dissector_handle_t new_create_dissector_handle_with_name(new_dissector_t dissector, const int proto, const char* name); +/** Destroy an anonymous handle for a dissector. */ +WS_DLL_PUBLIC void destroy_dissector_handle(dissector_handle_t handle); + /** Call a dissector through a handle and if no dissector was found * pass it over to the "data" dissector instead. * @@ -699,6 +708,8 @@ WS_DLL_PUBLIC void dissector_dump_heur_decodes(void); * dissector has been called. */ WS_DLL_PUBLIC void register_postdissector(dissector_handle_t); +WS_DLL_PUBLIC void deregister_postdissector(dissector_handle_t handle); + extern gboolean have_postdissector(void); extern void call_all_postdissectors(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); diff --git a/epan/prefs.c b/epan/prefs.c index 24cfdd8441..7c5613940c 100644 --- a/epan/prefs.c +++ b/epan/prefs.c @@ -305,6 +305,27 @@ prefs_register_module(module_t *parent, const char *name, const char *title, FALSE, apply_cb, use_gui); } +static void +prefs_deregister_module(module_t *parent, const char *name, const char *title) +{ + /* Remove this module from the list of all modules */ + module_t *module = (module_t *)wmem_tree_remove_string(prefs_modules, name, WMEM_TREE_STRING_NOCASE); + + if (!module) + return; + + if (parent == NULL) { + /* Remove from top */ + wmem_tree_remove_string(prefs_top_level_modules, title, WMEM_TREE_STRING_NOCASE); + } else if (parent->submodules) { + /* Remove from parent */ + wmem_tree_remove_string(parent->submodules, title, WMEM_TREE_STRING_NOCASE); + } + + free_module_prefs(module, NULL); + wmem_free(wmem_epan_scope(), module); +} + /* * Register a subtree that will have modules under it. * Specify the module under which to register it or NULL to register it @@ -454,6 +475,15 @@ prefs_register_protocol(int id, void (*apply_cb)(void)) proto_get_protocol_name(id), apply_cb, TRUE); } +void +prefs_deregister_protocol (int id) +{ + protocol_t *protocol = find_protocol_by_id(id); + prefs_deregister_module (protocols_module, + proto_get_protocol_filter_name(id), + proto_get_protocol_short_name(protocol)); +} + module_t * prefs_register_protocol_subtree(const char *subtree, int id, void (*apply_cb)(void)) { @@ -3331,6 +3361,7 @@ read_prefs_file(const char *pf_path, FILE *pf, /* Try to read in the profile name in the first line of the preferences file. */ if (fscanf(pf, "# Configuration file for %127[^\r\n]", ver) == 1) { /* Assume trailing period and remove it */ + g_free(prefs.saved_at_version); prefs.saved_at_version = g_strndup(ver, strlen(ver) - 1); } rewind(pf); diff --git a/epan/prefs.h b/epan/prefs.h index 03881edfb7..ec4e0c4f1f 100644 --- a/epan/prefs.h +++ b/epan/prefs.h @@ -289,6 +289,11 @@ module_t *prefs_register_subtree(module_t *parent, const char *title, */ WS_DLL_PUBLIC module_t *prefs_register_protocol(int id, void (*apply_cb)(void)); +/** + * Deregister preferences from a protocol. + */ +WS_DLL_PUBLIC void prefs_deregister_protocol(int id); + /* * Register that a statistical tap has preferences. * diff --git a/epan/proto.c b/epan/proto.c index 26fe71f974..28c9ff792a 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -324,6 +324,7 @@ static GPtrArray *deregistered_data = NULL; if((guint)hfindex >= gpa_hfinfo.len && getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG")) \ g_error("Unregistered hf! index=%d", hfindex); \ DISSECTOR_ASSERT_HINT((guint)hfindex < gpa_hfinfo.len, "Unregistered hf!"); \ + DISSECTOR_ASSERT_HINT(gpa_hfinfo.hfi[hfindex] != NULL, "Unregistered hf!"); \ hfinfo = gpa_hfinfo.hfi[hfindex]; /* List which stores protocols and fields that have been registered */ @@ -5240,6 +5241,48 @@ proto_register_protocol(const char *name, const char *short_name, return proto_id; } +gboolean +proto_deregister_protocol(const char *short_name) +{ + protocol_t *protocol; + header_field_info *hfinfo; + int proto_id; + gint *key; + guint i; + + proto_id = proto_get_id_by_short_name(short_name); + protocol = find_protocol_by_id(proto_id); + if (protocol == NULL) + return FALSE; + + key = (gint *)g_malloc(sizeof(gint)); + *key = wrs_str_hash(protocol->name); + + g_hash_table_remove(proto_names, key); + g_free(key); + + g_hash_table_remove(proto_short_names, (gpointer)short_name); + g_hash_table_remove(proto_filter_names, (gpointer)protocol->filter_name); + + for (i = 0; i < protocol->fields->len; i++) { + hfinfo = (header_field_info *)g_ptr_array_index(protocol->fields, i); + g_hash_table_steal(gpa_name_map, hfinfo->abbrev); + g_ptr_array_add(deregistered_fields, gpa_hfinfo.hfi[hfinfo->id]); + } + g_ptr_array_free(protocol->fields, TRUE); + + /* Remove this protocol from the list of known protocols */ + protocols = g_list_remove(protocols, protocol); + + g_ptr_array_add(deregistered_fields, gpa_hfinfo.hfi[proto_id]); + g_hash_table_steal(gpa_name_map, protocol->filter_name); + + g_free((gchar *)protocol->short_name); + g_free(protocol); + + return TRUE; +} + void proto_mark_private(const int proto_id) { @@ -5641,9 +5684,9 @@ proto_register_fields_manual(const int parent, header_field_info **hfi, const in } } -/* unregister already registered fields */ +/* deregister already registered fields */ void -proto_unregister_field (const int parent, gint hf_id) +proto_deregister_field (const int parent, gint hf_id) { header_field_info *hfi; protocol_t *proto; diff --git a/epan/proto.h b/epan/proto.h index 554754a2e1..2e9e1bbe09 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -1998,6 +1998,12 @@ proto_item_fill_label(field_info *fi, gchar *label_str); WS_DLL_PUBLIC int proto_register_protocol(const char *name, const char *short_name, const char *filter_name); +/** Deregister a protocol. + @param short_name abbreviated name of the protocol + @return TRUE if protocol is removed */ +WS_DLL_PUBLIC gboolean +proto_deregister_protocol(const char *short_name); + /** Mark protocol as private @param proto_id the handle of the protocol */ WS_DLL_PUBLIC @@ -2035,18 +2041,18 @@ WS_DLL_PUBLIC void proto_register_fields_section(const int parent, header_field_ WS_DLL_PUBLIC void proto_register_field_array(const int parent, hf_register_info *hf, const int num_records); -/** Unregister an already registered field. +/** Deregister an already registered field. @param parent the protocol handle from proto_register_protocol() @param hf_id the field to deregister */ WS_DLL_PUBLIC void -proto_unregister_field (const int parent, gint hf_id); +proto_deregister_field (const int parent, gint hf_id); /** Add data to be freed when deregistered fields are freed. @param data a pointer to data to free */ WS_DLL_PUBLIC void proto_add_deregistered_data (void *data); -/** Free fields deregistered in proto_unregister_field(). */ +/** Free fields deregistered in proto_deregister_field(). */ WS_DLL_PUBLIC void proto_free_deregistered_fields (void); diff --git a/epan/wmem/wmem_tree.c b/epan/wmem/wmem_tree.c index 1db2923a31..d82dc95b75 100644 --- a/epan/wmem/wmem_tree.c +++ b/epan/wmem/wmem_tree.c @@ -561,6 +561,17 @@ wmem_tree_lookup_string(wmem_tree_t* tree, const gchar* k, guint32 flags) return wmem_tree_lookup(tree, k, cmp); } +void * +wmem_tree_remove_string(wmem_tree_t* tree, const gchar* k, guint32 flags) +{ + void *ret = wmem_tree_lookup_string(tree, k, flags); + if (ret) { + /* Not really a remove, but set data to NULL so the lookup don't find it */ + wmem_tree_insert_string(tree, k, NULL, flags); + } + return ret; +} + static void * create_sub_tree(void* d) { @@ -655,10 +666,11 @@ wmem_tree_foreach_nodes(wmem_tree_node_t* node, wmem_foreach_func callback, } } - if (node->is_subtree == TRUE) { + if (node->is_subtree) { stop_traverse = wmem_tree_foreach((wmem_tree_t *)node->data, callback, user_data); - } else { + } else if (node->data) { + /* No callback for "removed" nodes */ stop_traverse = callback(node->data, user_data); } diff --git a/epan/wmem/wmem_tree.h b/epan/wmem/wmem_tree.h index 4c22824e18..2b551a5441 100644 --- a/epan/wmem/wmem_tree.h +++ b/epan/wmem/wmem_tree.h @@ -128,6 +128,13 @@ WS_DLL_PUBLIC void * wmem_tree_lookup_string(wmem_tree_t* tree, const gchar* key, guint32 flags); +/** Remove the value under a string key. This is not really a remove, but the + * value is set to NULL so that wmem_tree_lookup_string not will find it. + * See wmem_tree_insert_string for an explanation of flags. */ +WS_DLL_PUBLIC +void * +wmem_tree_remove_string(wmem_tree_t* tree, const gchar* key, guint32 flags); + typedef struct _wmem_tree_key_t { guint32 length; /**< length in guint32 words */ guint32 *key; diff --git a/epan/wslua/init_wslua.c b/epan/wslua/init_wslua.c index f0d64b3e3f..39b3447f23 100644 --- a/epan/wslua/init_wslua.c +++ b/epan/wslua/init_wslua.c @@ -349,10 +349,10 @@ static int init_error_handler(lua_State* LS) { } +static gboolean init_routine_initialized = FALSE; static void wslua_init_routine(void) { - static gboolean initialized = FALSE; - if ( ! initialized ) { + if ( ! init_routine_initialized ) { /* * This must be done only once during the entire life of * tshark/wireshark, because it must be done only once per the life of @@ -364,7 +364,7 @@ static void wslua_init_routine(void) { * Lua states, we'll need to change this. */ lua_prime_all_fields(NULL); - initialized = TRUE; + init_routine_initialized = TRUE; } if (L) { @@ -406,7 +406,7 @@ static int lua_main_error_handler(lua_State* LS) { return 0; } -static void wslua_add_plugin(gchar *name, gchar *version, gchar *filename) +static void wslua_add_plugin(const gchar *name, const gchar *version, const gchar *filename) { wslua_plugin *new_plug, *lua_plug; @@ -422,12 +422,26 @@ static void wslua_add_plugin(gchar *name, gchar *version, gchar *filename) lua_plug->next = new_plug; } - new_plug->name = name; - new_plug->version = version; - new_plug->filename = filename; + new_plug->name = g_strdup(name); + new_plug->version = g_strdup(version); + new_plug->filename = g_strdup(filename); new_plug->next = NULL; } +static void wslua_clear_plugin_list(void) +{ + wslua_plugin *lua_plug; + + while (wslua_plugin_list) { + lua_plug = wslua_plugin_list; + wslua_plugin_list = wslua_plugin_list->next; + g_free (lua_plug->name); + g_free (lua_plug->version); + g_free (lua_plug->filename); + g_free (lua_plug); + } +} + static int lua_script_push_args(const int script_num) { gchar* argname = g_strdup_printf("lua_script%d", script_num); const gchar* argvalue = NULL; @@ -562,9 +576,7 @@ static gboolean lua_load_plugin_script(const gchar* name, const int file_count) { if (lua_load_script(filename, dirname, file_count)) { - wslua_add_plugin(g_strdup(name), - g_strdup(get_current_plugin_version()), - g_strdup(filename)); + wslua_add_plugin(name, get_current_plugin_version(), filename); clear_current_plugin_version(); return TRUE; } @@ -705,13 +717,14 @@ wslua_get_expert_field(const int group, const int severity) return &ei_lua_error; } -int wslua_init(register_cb cb, gpointer client_data) { +void wslua_init(register_cb cb, gpointer client_data) { gchar* filename; const gchar *script_filename; const funnel_ops_t* ops = funnel_get_funnel_ops(); gboolean run_anyway = FALSE; expert_module_t* expert_lua; int file_count = 1; + static gboolean first_time = TRUE; static hf_register_info hf[] = { { &hf_wslua_fake, @@ -803,17 +816,19 @@ int wslua_init(register_cb cb, gpointer client_data) { { &ei_lua_error, { "_ws.lua.error", PI_UNDECODED, PI_ERROR ,"Lua Error", EXPFILL }}, }; - ws_lua_ei = ei; - ws_lua_ei_len = array_length(ei); + if (first_time) { + ws_lua_ei = ei; + ws_lua_ei_len = array_length(ei); - /* set up the logger */ - g_log_set_handler(LOG_DOMAIN_LUA, (GLogLevelFlags)(G_LOG_LEVEL_CRITICAL| + /* set up the logger */ + g_log_set_handler(LOG_DOMAIN_LUA, (GLogLevelFlags)(G_LOG_LEVEL_CRITICAL| G_LOG_LEVEL_WARNING| G_LOG_LEVEL_MESSAGE| G_LOG_LEVEL_INFO| G_LOG_LEVEL_DEBUG), ops ? ops->logger : basic_logger, NULL); + } if (!L) { L = luaL_newstate(); @@ -821,10 +836,12 @@ int wslua_init(register_cb cb, gpointer client_data) { WSLUA_INIT(L); - proto_lua = proto_register_protocol("Lua Dissection", "Lua Dissection", "_ws.lua"); - proto_register_field_array(proto_lua, hf, array_length(hf)); - expert_lua = expert_register_protocol(proto_lua); - expert_register_field_array(expert_lua, ei, array_length(ei)); + if (first_time) { + proto_lua = proto_register_protocol("Lua Dissection", "Lua Dissection", "_ws.lua"); + proto_register_field_array(proto_lua, hf, array_length(hf)); + expert_lua = expert_register_protocol(proto_lua); + expert_register_field_array(expert_lua, ei, array_length(ei)); + } lua_atpanic(L,wslua_panic); @@ -878,7 +895,7 @@ int wslua_init(register_cb cb, gpointer client_data) { /* disable lua */ lua_close(L); L = NULL; - return 0; + first_time = FALSE; } lua_pop(L,1); /* pop the getglobal result */ @@ -926,9 +943,11 @@ int wslua_init(register_cb cb, gpointer client_data) { } } - /* at this point we're set up so register the init and cleanup routines */ - register_init_routine(wslua_init_routine); - register_cleanup_routine(wslua_cleanup_routine); + if (first_time) { + /* at this point we're set up so register the init and cleanup routines */ + register_init_routine(wslua_init_routine); + register_cleanup_routine(wslua_cleanup_routine); + } /* * after this point it is too late to register a menu @@ -946,16 +965,44 @@ int wslua_init(register_cb cb, gpointer client_data) { Proto_commit(L); - return 0; + first_time = FALSE; +} + +/* @TODO: Reloading Lua plugins. + * + * - Deregister FileHandlers + * - Support deregister ProtoField with existing abbrev (same_name_hfinfo) + * - Add a progress dialog when reloading many plugins + * - Search for memory leakages in wslua functions + */ +void wslua_reload_plugins (register_cb cb, gpointer client_data) { + const funnel_ops_t* ops = funnel_get_funnel_ops(); + + if (cb) + (*cb)(RA_LUA_DEREGISTER, NULL, client_data); + + if (ops->close_dialogs) + ops->close_dialogs(); + + wslua_cleanup(); /* deregister */ + wslua_init(cb, client_data); /* reinitialize */ } -int wslua_cleanup(void) { +void wslua_cleanup(void) { /* cleanup lua */ - if (!L) { + if (L) { + wslua_deregister_protocols(L); + wslua_deregister_dissector_tables(L); + wslua_deregister_listeners(L); + wslua_deregister_filehandlers(L); + wslua_deregister_menus(); + wslua_clear_plugin_list(); + proto_free_deregistered_fields(); + lua_close(L); L = NULL; } - return 0; + init_routine_initialized = FALSE; } lua_State* wslua_state(void) { return L; } diff --git a/epan/wslua/init_wslua.h b/epan/wslua/init_wslua.h index e57818c081..850cc2e9e8 100644 --- a/epan/wslua/init_wslua.h +++ b/epan/wslua/init_wslua.h @@ -27,9 +27,11 @@ extern "C" { #endif /* __cplusplus */ +#include "register.h" #include "ws_symbol_export.h" WS_DLL_PUBLIC int wslua_count_plugins(void); +WS_DLL_PUBLIC void wslua_reload_plugins (register_cb cb, gpointer client_data); typedef void (*wslua_plugin_description_callback)(const char *, const char *, const char *, const char *, diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h index b19725d258..7ad7926db6 100644 --- a/epan/wslua/wslua.h +++ b/epan/wslua/wslua.h @@ -188,12 +188,19 @@ typedef struct _wslua_proto_t { expert_module_t *expert_module; module_t *prefs_module; dissector_handle_t handle; + GArray *hfa; + GArray *etta; + GArray *eia; gboolean is_postdissector; + gboolean expired; } wslua_proto_t; struct _wslua_distbl_t { dissector_table_t table; const gchar* name; + const gchar* ui_name; + gboolean created; + gboolean expired; }; struct _wslua_col_info { @@ -716,8 +723,8 @@ extern void clear_outstanding_FieldInfo(void); extern void wslua_print_stack(char* s, lua_State* L); -extern int wslua_init(register_cb cb, gpointer client_data); -extern int wslua_cleanup(void); +extern void wslua_init(register_cb cb, gpointer client_data); +extern void wslua_cleanup(void); extern tap_extractor_t wslua_get_tap_extractor(const gchar* name); extern int wslua_set_tap_enums(lua_State* L); @@ -733,6 +740,12 @@ extern int luaopen_rex_glib(lua_State *L); extern const gchar* get_current_plugin_version(void); extern void clear_current_plugin_version(void); +extern int wslua_deregister_protocols(lua_State* L); +extern int wslua_deregister_dissector_tables(lua_State* L); +extern int wslua_deregister_listeners(lua_State* L); +extern int wslua_deregister_filehandlers(lua_State* L); +extern void wslua_deregister_menus(void); + #endif /* diff --git a/epan/wslua/wslua_dissector.c b/epan/wslua/wslua_dissector.c index d3ccc0413f..7472d76037 100644 --- a/epan/wslua/wslua_dissector.c +++ b/epan/wslua/wslua_dissector.c @@ -168,6 +168,8 @@ WSLUA_CLASS_DEFINE(DissectorTable,NOP,NOP); Useful to add more dissectors to a table so that they appear in the Decode As... dialog. */ +static int dissectortable_table_ref = LUA_NOREF; + WSLUA_CONSTRUCTOR DissectorTable_new (lua_State *L) { /* Creates a new DissectorTable for your dissector's use. */ #define WSLUA_ARG_DissectorTable_new_TABLENAME 1 /* The short name of the table. */ @@ -201,6 +203,15 @@ WSLUA_CONSTRUCTOR DissectorTable_new (lua_State *L) { dt->table = register_dissector_table(name, ui_name, type, base); dt->name = name; + dt->ui_name = ui_name; + dt->created = TRUE; + dt->expired = FALSE; + + lua_rawgeti(L, LUA_REGISTRYINDEX, dissectortable_table_ref); + lua_pushstring(L, name); + pushDissectorTable(L, dt); + lua_settable(L, -3); + pushDissectorTable(L, dt); } WSLUA_RETURN(1); /* The newly created DissectorTable. */ @@ -284,6 +295,9 @@ WSLUA_CONSTRUCTOR DissectorTable_get (lua_State *L) { DissectorTable dt = (DissectorTable)g_malloc(sizeof(struct _wslua_distbl_t)); dt->table = table; dt->name = g_strdup(name); + dt->ui_name = NULL; + dt->created = FALSE; + dt->expired = FALSE; pushDissectorTable(L, dt); @@ -648,7 +662,17 @@ WSLUA_METAMETHOD DissectorTable__tostring(lua_State* L) { /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int DissectorTable__gc(lua_State* L _U_) { - /* do NOT free DissectorTable */ + DissectorTable dt = toDissectorTable(L,1); + + if (dt->created && !dt->expired) { + /* Created DissectorTable will pass GC two times */ + dt->expired = TRUE; + } else { + g_free((char *)dt->name); + g_free((char *)dt->ui_name); + g_free(dt); + } + return 0; } @@ -674,9 +698,27 @@ WSLUA_META DissectorTable_meta[] = { int DissectorTable_register(lua_State* L) { WSLUA_REGISTER_CLASS(DissectorTable); + + lua_newtable (L); + dissectortable_table_ref = luaL_ref(L, LUA_REGISTRYINDEX); + return 0; } +int wslua_deregister_dissector_tables(lua_State* L) { + /* for each registered DissectorTable do... */ + lua_rawgeti(L, LUA_REGISTRYINDEX, dissectortable_table_ref); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + DissectorTable dt = checkDissectorTable(L, -1); + if (dt->created) { + deregister_dissector_table(dt->name); + } + } + + lua_pop(L, 1); /* dissector_table_ref */ + + return 0; +} /* * Editor modelines - http://www.wireshark.org/tools/modelines.html diff --git a/epan/wslua/wslua_field.c b/epan/wslua/wslua_field.c index 2321a118c3..1429470397 100644 --- a/epan/wslua/wslua_field.c +++ b/epan/wslua/wslua_field.c @@ -590,7 +590,7 @@ void lua_prime_all_fields(proto_tree* tree _U_) { g_ptr_array_free(wanted_fields,TRUE); wanted_fields = NULL; - if (fake_tap) { + if (fake_tap && fake_tap_filter->len > strlen("frame")) { /* a boring tap :-) */ GString* error = register_tap_listener("frame", &fake_tap, @@ -611,8 +611,10 @@ void lua_prime_all_fields(proto_tree* tree _U_) { g_free(err_msg); } } + } else if (fake_tap) { + remove_tap_listener(&fake_tap); + fake_tap = FALSE; } - } WSLUA_CONSTRUCTOR Field_new(lua_State *L) { diff --git a/epan/wslua/wslua_file_handler.c b/epan/wslua/wslua_file_handler.c index 1ea8cb4555..033686bf17 100644 --- a/epan/wslua/wslua_file_handler.c +++ b/epan/wslua/wslua_file_handler.c @@ -982,6 +982,11 @@ int FileHandler_register(lua_State* L) { return 0; } +int wslua_deregister_filehandlers(lua_State* L _U_) { + /* TODO: Implement */ + return 0; +} + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html diff --git a/epan/wslua/wslua_gui.c b/epan/wslua/wslua_gui.c index 0586293aa3..1fc3baeee7 100644 --- a/epan/wslua/wslua_gui.c +++ b/epan/wslua/wslua_gui.c @@ -121,8 +121,9 @@ WSLUA_FUNCTION wslua_register_menu(lua_State* L) { /* Register a menu item in o WSLUA_RETURN(0); } - - +void wslua_deregister_menus(void) { + funnel_deregister_menus(lua_menu_callback); +} struct _dlg_cb_data { lua_State* L; @@ -553,6 +554,20 @@ WSLUA_METHOD TextWindow_get_text(lua_State* L) { /* Get the text of the window * WSLUA_RETURN(1); /* The `TextWindow`'s text. */ } +WSLUA_METHOD TextWindow_close(lua_State* L) { /* Close the window */ + TextWindow tw = checkTextWindow(L,1); + + if (!ops->destroy_text_window) { + WSLUA_ERROR(TextWindow_get_text,"GUI not available"); + return 0; + } + + ops->destroy_text_window(tw->ws_tw); + tw->ws_tw = NULL; + + return 0; +} + /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int TextWindow__gc(lua_State* L) { TextWindow tw = toTextWindow(L,1); @@ -666,7 +681,6 @@ WSLUA_METHOD TextWindow_add_button(lua_State* L) { WSLUA_METHODS TextWindow_methods[] = { WSLUA_CLASS_FNREG(TextWindow,new), WSLUA_CLASS_FNREG(TextWindow,set), - WSLUA_CLASS_FNREG(TextWindow,new), WSLUA_CLASS_FNREG(TextWindow,append), WSLUA_CLASS_FNREG(TextWindow,prepend), WSLUA_CLASS_FNREG(TextWindow,clear), @@ -674,6 +688,7 @@ WSLUA_METHODS TextWindow_methods[] = { WSLUA_CLASS_FNREG(TextWindow,set_editable), WSLUA_CLASS_FNREG(TextWindow,get_text), WSLUA_CLASS_FNREG(TextWindow,add_button), + WSLUA_CLASS_FNREG(TextWindow,close), { NULL, NULL } }; diff --git a/epan/wslua/wslua_listener.c b/epan/wslua/wslua_listener.c index 64ed0610ff..cd4509985a 100644 --- a/epan/wslua/wslua_listener.c +++ b/epan/wslua/wslua_listener.c @@ -183,6 +183,18 @@ static void lua_tap_draw(void *tapdata) { } } +/* TODO: we should probably use a Lua table here */ +static GPtrArray *listeners = NULL; + +static void deregister_Listener (lua_State* L _U_, Listener tap) { + if (tap->all_fields) { + epan_set_always_visible(FALSE); + tap->all_fields = FALSE; + } + + remove_tap_listener(tap); +} + WSLUA_CONSTRUCTOR Listener_new(lua_State* L) { /* Creates a new `Listener` listener object. */ #define WSLUA_OPTARG_Listener_new_TAP 1 /* The name of this tap. */ @@ -231,6 +243,8 @@ WSLUA_CONSTRUCTOR Listener_new(lua_State* L) { epan_set_always_visible(TRUE); } + g_ptr_array_add(listeners, tap); + pushListener(L,tap); WSLUA_RETURN(1); /* The newly created Listener listener object */ } @@ -272,13 +286,10 @@ WSLUA_METHOD Listener_remove(lua_State* L) { /* Removes a tap `Listener`. */ Listener tap = checkListener(L,1); - if (tap->all_fields) { - epan_set_always_visible(FALSE); - tap->all_fields = FALSE; + if (g_ptr_array_remove(listeners, tap)) { + deregister_Listener(L, tap); } - remove_tap_listener(tap); - return 0; } @@ -326,7 +337,16 @@ WSLUA_ATTRIBUTE_FUNC_SETTER(Listener,reset); static int Listener__gc(lua_State* L _U_) { - /* do NOT free Listener, it's never free'd */ + Listener tap = toListener(L, 1); + + if (listeners && g_ptr_array_remove(listeners, tap)) { + deregister_Listener(L, tap); + } + + g_free(tap->filter); + g_free(tap->name); + g_free(tap); + return 0; } @@ -355,11 +375,28 @@ WSLUA_META Listener_meta[] = { int Listener_register(lua_State* L) { wslua_set_tap_enums(L); + + listeners = g_ptr_array_new(); + WSLUA_REGISTER_CLASS(Listener); WSLUA_REGISTER_ATTRIBUTES(Listener); return 0; } +static void deregister_tap_listener (gpointer data, gpointer userdata) { + lua_State *L = (lua_State *) userdata; + Listener tap = (Listener) data; + deregister_Listener(L, tap); +} + +int wslua_deregister_listeners(lua_State* L) { + g_ptr_array_foreach(listeners, deregister_tap_listener, L); + g_ptr_array_free(listeners, FALSE); + listeners = NULL; + + return 0; +} + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * diff --git a/epan/wslua/wslua_pref.c b/epan/wslua/wslua_pref.c index cdde74d0c8..b154a27a69 100644 --- a/epan/wslua/wslua_pref.c +++ b/epan/wslua/wslua_pref.c @@ -232,11 +232,13 @@ static range_t* get_range(lua_State *L, int idx_r, int idx_m) return ret; } + /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int Pref__gc(lua_State* L) { - Pref pref = checkPref(L,1); + Pref pref = toPref(L,1); - if (pref && ! pref->name) { + if (! pref->name) { + /* Only free unregistered and deregistered Pref */ g_free(pref->label); g_free(pref->desc); if (pref->type == PREF_STRING) @@ -433,7 +435,7 @@ WSLUA_METAMETHOD Prefs__index(lua_State* L) { /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int Prefs__gc(lua_State* L _U_) { - /* do NOT free Prefs, it's never free'd */ + /* do NOT free Prefs, it's a static part of Proto */ return 0; } diff --git a/epan/wslua/wslua_proto.c b/epan/wslua/wslua_proto.c index 9f7d2f8b50..155d0fe194 100644 --- a/epan/wslua/wslua_proto.c +++ b/epan/wslua/wslua_proto.c @@ -5,6 +5,7 @@ * * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org> * (c) 2007, Tamas Regos <tamas.regos@ericsson.com> + * (c) 2014, Stig Bjorlykke <stig@bjorlykke.org> * * Wireshark - Network traffic analyzer * By Gerald Combs <gerald@wireshark.org> @@ -122,6 +123,7 @@ WSLUA_CONSTRUCTOR Proto_new(lua_State* L) { proto->hfid = proto_register_protocol(proto->desc,hiname,loname); proto->ett = -1; proto->is_postdissector = FALSE; + proto->expired = FALSE; lua_newtable (L); proto->fields = luaL_ref(L, LUA_REGISTRYINDEX); @@ -479,7 +481,18 @@ static int Proto_set_experts(lua_State* L) { /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int Proto__gc(lua_State* L _U_) { - /* do NOT free Proto, it's never free'd */ + /* Proto is registered twice, once in protocols_table_ref and once returned from Proto_new. + * It will not be freed unless deregistered. + */ + Proto proto = toProto(L,1); + + if (!proto->expired) { + proto->expired = TRUE; + } else if (proto->hfid == -2) { + /* Only free deregistered Proto */ + g_free(proto); + } + return 0; } @@ -553,6 +566,71 @@ ProtoField wslua_is_field_available(lua_State* L, const char* field_abbr) { return NULL; } +int wslua_deregister_protocols(lua_State* L) { + /* for each registered Proto protocol do... */ + lua_rawgeti(L, LUA_REGISTRYINDEX, protocols_table_ref); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + Proto proto; + proto = checkProto(L, -1); + + if (proto->handle) { + deregister_dissector(proto->loname); + } + if (proto->prefs_module) { + Pref pref; + prefs_deregister_protocol(proto->hfid); + for (pref = proto->prefs.next; pref; pref = pref->next) { + g_free(pref->name); + pref->name = NULL; /* Deregister Pref, freed in Pref__gc */ + } + } + if (proto->expert_module) { + expert_deregister_protocol(proto->expert_module); + } + proto_deregister_protocol(proto->name); + + /* for each registered ProtoField do... */ + lua_rawgeti(L, LUA_REGISTRYINDEX, proto->fields); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + ProtoField f = checkProtoField(L, -1); + f->hfid = -2; /* Deregister ProtoField, freed in ProtoField__gc */ + } + lua_pop(L, 1); + + /* for each registered ProtoExpert do... */ + lua_rawgeti(L, LUA_REGISTRYINDEX, proto->expert_info_table_ref); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + ProtoExpert pe = checkProtoExpert(L,-1); + pe->ids.hf = -2; /* Deregister ProtoExpert, freed in ProtoExpert__gc */ + } + lua_pop(L, 1); + + if (proto->hfa->len) { + proto_add_deregistered_data(g_array_free(proto->hfa,FALSE)); + } else { + g_array_free(proto->hfa,TRUE); + } + + if (proto->etta->len) { + proto_add_deregistered_data(g_array_free(proto->etta,FALSE)); + } else { + g_array_free(proto->etta,TRUE); + } + + if (proto->eia->len) { + proto_add_deregistered_data(g_array_free(proto->eia,FALSE)); + } else { + g_array_free(proto->eia,TRUE); + } + + proto->hfid = -2; /* Deregister Proto, freed in Proto__gc */ + } + + lua_pop(L, 1); /* protocols_table_ref */ + + return 0; +} + int Proto_commit(lua_State* L) { lua_settop(L,0); /* the following gets the table of registered Proto protocols and puts it on the stack (index=1) */ @@ -566,16 +644,15 @@ int Proto_commit(lua_State* L) { to lua_pop(L, 2), and when lua_next() returns 0 (no more table entries), it will have pop'ed the final key itself, leaving just the protocols_table_ref table on the stack. */ - GArray* hfa = g_array_new(TRUE,TRUE,sizeof(hf_register_info)); - GArray* etta = g_array_new(TRUE,TRUE,sizeof(gint*)); - GArray* eia = g_array_new(TRUE,TRUE,sizeof(ei_register_info)); + Proto proto = checkProto(L,3); gint* ettp = NULL; - Proto proto; - /* const gchar* proto_name = lua_tostring(L,2); */ - proto = checkProto(L,3); + + proto->hfa = g_array_new(TRUE,TRUE,sizeof(hf_register_info)); + proto->etta = g_array_new(TRUE,TRUE,sizeof(gint*)); + proto->eia = g_array_new(TRUE,TRUE,sizeof(ei_register_info)); ettp = &(proto->ett); - g_array_append_val(etta,ettp); + g_array_append_val(proto->etta,ettp); /* get the Lua table of ProtoFields, push it on the stack (index=3) */ lua_rawgeti(L, LUA_REGISTRYINDEX, proto->fields); @@ -600,13 +677,13 @@ int Proto_commit(lua_State* L) { } f->hfid = -1; - g_array_append_val(hfa,hfri); - g_array_append_val(etta,ettp); + g_array_append_val(proto->hfa,hfri); + g_array_append_val(proto->etta,ettp); } /* register the proto fields */ - proto_register_field_array(proto->hfid,(hf_register_info*)(void*)hfa->data,hfa->len); - proto_register_subtree_array((gint**)(void*)etta->data,etta->len); + proto_register_field_array(proto->hfid,(hf_register_info*)(void*)proto->hfa->data,proto->hfa->len); + proto_register_subtree_array((gint**)(void*)proto->etta->data,proto->etta->len); lua_pop(L,1); /* pop the table of ProtoFields */ @@ -630,15 +707,10 @@ int Proto_commit(lua_State* L) { return luaL_error(L,"expert fields can be registered only once"); } - g_array_append_val(eia,eiri); + g_array_append_val(proto->eia,eiri); } - expert_register_field_array(proto->expert_module, (ei_register_info*)(void*)eia->data, eia->len); - - /* XXX: the registration routines say to use static arrays only, so is this safe? */ - g_array_free(hfa,FALSE); - g_array_free(etta,FALSE); - g_array_free(eia,FALSE); + expert_register_field_array(proto->expert_module, (ei_register_info*)(void*)proto->eia->data, proto->eia->len); /* Proto object and ProtoFields table will be pop'ed by lua_pop(L, 2) in for statement */ } diff --git a/epan/wslua/wslua_proto_expert.c b/epan/wslua/wslua_proto_expert.c index f1a36c13e3..8a8079152c 100644 --- a/epan/wslua/wslua_proto_expert.c +++ b/epan/wslua/wslua_proto_expert.c @@ -99,17 +99,11 @@ WSLUA_METAMETHOD ProtoExpert__tostring(lua_State* L) { static int ProtoExpert__gc(lua_State* L) { ProtoExpert pe = toProtoExpert(L,1); - /* - * A garbage collector for ProtoExpert makes little sense. - * Even if this cannot be used anymore because it has gone out of scope, - * we can destroy the ProtoExpert only if it is not part of a registered Proto, - * if it actually belongs to one we need to preserve it as it is pointed by - * a expert code causing a crash or memory corruption. - */ - - if (pe) { - luaL_argerror(L,1,"BUG: ProtoExpert_gc called for something not ProtoExpert"); - /* g_assert() ?? */ + if (pe->ids.hf == -2) { + /* Only free unregistered and deregistered ProtoExpert */ + g_free((gchar *)pe->abbrev); + g_free((gchar *)pe->text); + g_free(pe); } return 0; diff --git a/epan/wslua/wslua_proto_field.c b/epan/wslua/wslua_proto_field.c index bb91b6cbe8..f6d4421c99 100644 --- a/epan/wslua/wslua_proto_field.c +++ b/epan/wslua/wslua_proto_field.c @@ -916,21 +916,24 @@ WSLUA_METAMETHOD ProtoField__tostring(lua_State* L) { static int ProtoField__gc(lua_State* L) { ProtoField f = toProtoField(L,1); - /* - * A garbage collector for ProtoFields makes little sense. - * Even if This cannot be used anymore because it has gone out of scope, - * we can destroy the ProtoField only if it is not part of a ProtoFieldArray, - * if it actualy belongs to one we need to preserve it as it is pointed by - * a field array that may be registered afterwards causing a crash or memory corruption. - */ - - if (!f) { - luaL_argerror(L,1,"BUG: ProtoField_gc called for something not ProtoField"); - /* g_assert() ?? */ - } else if (f->hfid == -2) { - g_free(f->name); - g_free(f->abbrev); - g_free(f->blob); + if (f->hfid == -2) { + /* Only free unregistered and deregistered ProtoField */ + if (f->vs) { + if (f->type == FT_UINT64 || f->type == FT_INT64) { + val64_string *vs64 = (val64_string *)f->vs; + while (vs64->strptr) { + g_free((gchar *)vs64->strptr); + vs64++; + } + } else if (f->type != FT_BOOLEAN) { /* Other Integer types */ + value_string *vs = (value_string *)f->vs; + while (vs->strptr) { + g_free((gchar *)vs->strptr); + vs++; + } + } + g_free((void *)f->vs); + } g_free(f); } diff --git a/epan/wslua/wslua_tree.c b/epan/wslua/wslua_tree.c index 5a90d53c99..773b6b1c91 100644 --- a/epan/wslua/wslua_tree.c +++ b/epan/wslua/wslua_tree.c @@ -886,6 +886,7 @@ WSLUA_META TreeItem_meta[] = { int TreeItem_register(lua_State *L) { gint* etts[] = { &wslua_ett }; + wslua_ett = -1; /* Reset to support reload Lua plugins */ WSLUA_REGISTER_CLASS(TreeItem); WSLUA_REGISTER_ATTRIBUTES(TreeItem); outstanding_TreeItem = g_ptr_array_new(); |