From fcaa69157b008df2e95d41fa691913c1f796cf09 Mon Sep 17 00:00:00 2001 From: Bram Matthys Date: Wed, 22 Mar 2017 10:51:29 +0100 Subject: [PATCH] Fix crash when unloading (not reloading) module that uses ModData (#4903). --- src/moddata.c | 29 ++++++++++++++++++++--------- src/modules.c | 3 --- src/s_conf.c | 40 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/moddata.c b/src/moddata.c index 69126b55e..43e997bc0 100644 --- a/src/moddata.c +++ b/src/moddata.c @@ -187,7 +187,9 @@ void unload_moddata_commit(ModDataInfo *md) list_for_each_entry(acptr, &lclient_list, lclient_node) { if (md->free && moddata_client(acptr, md).ptr) - md->free(moddata_client(acptr, md).ptr); + { + md->free(&moddata_client(acptr, md)); + } memset(&moddata_client(acptr, md), 0, sizeof(ModData)); } break; @@ -198,7 +200,7 @@ void unload_moddata_commit(ModDataInfo *md) for (chptr = channel; chptr; chptr=chptr->nextch) { if (md->free && moddata_channel(chptr, md).ptr) - md->free(moddata_channel(chptr, md).ptr); + md->free(&moddata_channel(chptr, md)); memset(&moddata_channel(chptr, md), 0, sizeof(ModData)); } break; @@ -212,7 +214,7 @@ void unload_moddata_commit(ModDataInfo *md) for (m = chptr->members; m; m = m->next) { if (md->free && moddata_member(m, md).ptr) - md->free(moddata_member(m, md).ptr); + md->free(&moddata_member(m, md)); memset(&moddata_member(m, md), 0, sizeof(ModData)); } } @@ -229,7 +231,7 @@ void unload_moddata_commit(ModDataInfo *md) for (m = acptr->user->channel; m; m = m->next) { if (md->free && moddata_membership(m, md).ptr) - md->free(moddata_membership(m, md).ptr); + md->free(&moddata_membership(m, md)); memset(&moddata_membership(m, md), 0, sizeof(ModData)); } } @@ -239,12 +241,12 @@ void unload_moddata_commit(ModDataInfo *md) DelListItem(md, MDInfo); MyFree(md->name); - MyFree(MDInfo); + MyFree(md); } void ModDataDel(ModDataInfo *md) { - + /* Delete the reference to us first */ if (md->owner) { ModuleObject *mdobj; @@ -273,9 +275,8 @@ ModDataInfo *md, *md_next; for (md = MDInfo; md; md = md_next) { md_next = md->next; - if (md->owner) - abort(); /* shouldn't happen */ - unload_moddata_commit(md); + if (md->unloaded) + unload_moddata_commit(md); } } @@ -290,6 +291,16 @@ ModDataInfo *md; return NULL; } +int module_has_moddata(Module *mod) +{ + ModDataInfo *md; + + for (md = MDInfo; md; md = md->next) + if (md->owner == mod) + return 1; + + return 0; +} /** Set ModData for client (via variable name, string value) */ int moddata_client_set(aClient *acptr, char *varname, char *value) diff --git a/src/modules.c b/src/modules.c index 039e9dcf6..a3c71d729 100644 --- a/src/modules.c +++ b/src/modules.c @@ -867,9 +867,6 @@ vFP Module_SymX(char *name, Module **mptr) return NULL; } - - - void module_loadall(void) { iFP fp; diff --git a/src/s_conf.c b/src/s_conf.c index 51fd5862f..bce34e93c 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -257,6 +257,7 @@ extern void charsys_reset_pretest(void); int charsys_postconftest(void); void charsys_finish(void); int reloadable_perm_module_unloaded(void); +void special_delayed_unloading(void); int ssl_tests(void); @@ -1628,6 +1629,9 @@ int config_test_all(void) { return 0; } + + special_delayed_unloading(); + return 1; } @@ -9598,6 +9602,7 @@ int rehash_internal(aClient *cptr, aClient *sptr, int sig) unload_all_unused_snomasks(); unload_all_unused_umodes(); unload_all_unused_extcmodes(); + // unload_all_unused_moddata(); -- this will crash extcmodes_check_for_changes(); loop.ircd_rehashing = 0; remote_rehash_client = NULL; @@ -9996,9 +10001,9 @@ int ssl_tests(void) */ int reloadable_perm_module_unloaded(void) { -Module *m, *m2; -extern Module *Modules; -int ret = 0; + Module *m, *m2; + extern Module *Modules; + int ret = 0; for (m = Modules; m; m = m->next) { @@ -10019,5 +10024,34 @@ int ret = 0; } } } + return ret; } + +extern int module_has_moddata(Module *mod); + +/** Special hack for unloading modules with moddata */ +void special_delayed_unloading(void) +{ + Module *m, *m2; + extern Module *Modules; + + for (m = Modules; m; m = m->next) + { + if ((m->flags & MODFLAG_LOADED) && module_has_moddata(m) && !(m->options & MOD_OPT_PERM) && !(m->options & MOD_OPT_PERM_RELOADABLE)) + { + int found = 0; + for (m2 = Modules; m2; m2 = m2->next) + { + if ((m != m2) && !strcmp(m->header->name, m2->header->name)) + found = 1; + } + if (!found) + { + config_warn("Delaying module unloading of '%s' due to moddata", m->header->name); + m->flags |= MODFLAG_DELAYED; + EventAddEx(NULL, "e_unload_module_delayed", 5, 1, e_unload_module_delayed, m->header->name); + } + } + } +}