From 0083d8f5825714bb5a7c609ee19a2216e07f1cc4 Mon Sep 17 00:00:00 2001 From: Brandon L Black Date: Tue, 11 Sep 2018 17:21:16 +0000 Subject: [PATCH] dlclose() plugins on shutdown We suppressed/ignored the warning about leaking the dlopen handles long ago in Coverity, since the plugins stay loaded for the life of the daemon. However, with the current fork->execve model used for "replace", I can't be sure that leaking unclosed dlopen handles doesn't cause some kind of actual resource leak, especially on platforms I don't regularly test. Modern Linux/glibc doesn't show any visible leakage from it, but better safe than sorry since it's a simple fix. --- include/gdnsd/plugapi.h | 1 + libgdnsd/plugapi.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/gdnsd/plugapi.h b/include/gdnsd/plugapi.h index 6f951b89..c8871557 100644 --- a/include/gdnsd/plugapi.h +++ b/include/gdnsd/plugapi.h @@ -124,6 +124,7 @@ typedef void (*gdnsd_start_monitors_cb_t)(struct ev_loop* mon_loop); // pointers for all of the possibly-documented callbacks typedef struct { const char* name; + void* handle; bool config_loaded; gdnsd_load_config_cb_t load_config; gdnsd_map_res_cb_t map_res; diff --git a/libgdnsd/plugapi.c b/libgdnsd/plugapi.c index e544de5a..a4c31459 100644 --- a/libgdnsd/plugapi.c +++ b/libgdnsd/plugapi.c @@ -249,6 +249,8 @@ static plugin_t* gdnsd_plugin_load(const char* pname) pname, apiv_bopt, this_bopt); } + plug->handle = pptr; + # define PSETFUNC(x) plug->x = (gdnsd_ ## x ## _cb_t)plugin_dlsym(pptr, pname, #x); PSETFUNC(load_config) PSETFUNC(map_res) @@ -264,8 +266,6 @@ static plugin_t* gdnsd_plugin_load(const char* pname) PSETFUNC(start_monitors) # undef PSETFUNC - // leak of dlopen() handle "pptr" here is intentional. The code has no further - // use for it at this point, and we never dlclose() the plugins... return plug; } @@ -327,4 +327,7 @@ void gdnsd_plugins_action_exit(void) for (unsigned i = 0; i < num_plugins; i++) if (plugins[i]->exit) plugins[i]->exit(); + for (unsigned i = 0; i < num_plugins; i++) + if (dlclose(plugins[i]->handle)) + log_fatal("Failed to close() the '%s' plugin: %s", plugins[i]->name, dlerror()); }