]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
thread_local: Make sure that the thread_local atexit handler is called _last_
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 13 Mar 2020 01:10:51 +0000 (21:10 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 13 Mar 2020 01:18:08 +0000 (21:18 -0400)
13 files changed:
src/bin/radclient.c
src/bin/radict.c
src/bin/radiusd.c
src/bin/radsniff.c
src/bin/radsnmp.c
src/bin/radwho.c
src/bin/unit_test_attribute.c
src/bin/unit_test_map.c
src/bin/unit_test_module.c
src/lib/util/thread_local.c
src/lib/util/thread_local.h
src/modules/proto_control/radmin.c
src/modules/proto_dhcpv4/dhcpclient.c

index 417e03e743ce74be0418d7cad0628a26975b5837..06f76dc80586c059980a7462d76d65308b47e3ef 100644 (file)
@@ -1178,7 +1178,7 @@ int main(int argc, char **argv)
        int             parallel = 1;
        rc_request_t    *this;
        int             force_af = AF_UNSPEC;
-       TALLOC_CTX      *autofree = talloc_autofree_context();
+       TALLOC_CTX      *autofree;
 
        /*
         *      It's easier having two sets of flags to set the
@@ -1188,6 +1188,13 @@ int main(int argc, char **argv)
        fr_debug_lvl = 0;
        fr_log_fp = stdout;
 
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
+
 #ifndef NDEBUG
        if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
                fr_perror("radclient");
index 23c766a48a25582deff139d6c70ea1c806dbbf63..832e93a0ad7c3814e09384f1bd467ca27dc64519 100644 (file)
@@ -197,7 +197,14 @@ int main(int argc, char *argv[])
        bool            found = false;
        bool            export = false;
 
-       TALLOC_CTX      *autofree = talloc_autofree_context();
+       TALLOC_CTX      *autofree;
+
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
 
 #ifndef NDEBUG
        if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
index 97baab82fdf987d5bd6dca4e3b7b3d8160031d56..81a2ed41e0f9c41c2413772411865c74849d6fbc 100644 (file)
@@ -223,6 +223,10 @@ int main(int argc, char *argv[])
 #ifndef NDEBUG
        fr_time_delta_t exit_after = 0;
 #endif
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
 
        /*
         *      Setup talloc callbacks so we get useful errors
index fb08489a9ffc8591dec29d3fbdafc66e61bd6727..6c042137b787ede7394d8f51104cd4d4e640f3df 100644 (file)
@@ -2210,13 +2210,20 @@ int main(int argc, char *argv[])
        int             c;
        char const      *raddb_dir = RADDBDIR;
        char const      *dict_dir = DICTDIR;
-       TALLOC_CTX      *autofree = talloc_autofree_context();
+       TALLOC_CTX      *autofree;
 
        rs_stats_t      *stats;
 
        fr_debug_lvl = 1;
        fr_log_fp = stdout;
 
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
+
        /*
         *      Useful if using radsniff as a long running stats daemon
         */
index e3e49df331c1ebeec726117216fe0d2ad6be08f3..63d16572e24c0d35b18662a7f78522726bab61c1 100644 (file)
@@ -890,7 +890,7 @@ int main(int argc, char **argv)
        radsnmp_conf_t *conf;
        int             ret;
        int             sockfd;
-       TALLOC_CTX      *autofree = talloc_autofree_context();
+       TALLOC_CTX      *autofree;
 
        conf = talloc_zero(autofree, radsnmp_conf_t);
        conf->proto = IPPROTO_UDP;
@@ -900,6 +900,13 @@ int main(int argc, char **argv)
        conf->timeout = fr_time_delta_from_sec(3);
        conf->retries = 5;
 
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
+
 #ifndef NDEBUG
        if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
                fr_perror("radsnmp");
index 55643e863fe2d2ef8150b7347777283dd11482a0..f725acbc4459a0f07c273f344ae5356af039a90f 100644 (file)
@@ -197,11 +197,17 @@ int main(int argc, char **argv)
        uint32_t                nas_ip_address = INADDR_NONE;
        int                     zap = 0;
        fr_dict_t               *dict = NULL;
-       TALLOC_CTX              *autofree = talloc_autofree_context();
+       TALLOC_CTX              *autofree;
 
        char const              *p;
        main_config_t           *config;
 
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
 
 #ifndef NDEBUG
        if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
index 76cac1d4c25478c61b6e94654e0b9b7a70184bb8..5dcacb6d546ac89bda55c30a9884a5996547845a 100644 (file)
@@ -2348,7 +2348,7 @@ int main(int argc, char *argv[])
        int                     *inst = &c;
        CONF_SECTION            *cs;
        int                     ret = EXIT_SUCCESS;
-       TALLOC_CTX              *autofree = talloc_autofree_context();
+       TALLOC_CTX              *autofree;
        dl_module_loader_t      *dl_modules = NULL;
        bool                    exit_now = false;
 
@@ -2362,6 +2362,13 @@ int main(int argc, char *argv[])
        bool                    do_commands = false;
        bool                    do_usage = false;
 
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
+
 #ifndef NDEBUG
        if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
                fr_perror("unit_test_attribute");
index e9c15eacdeafffd66c8948e605574466e974a875..780fe89949f45a056ac8a602095fd8f73e549ae2 100644 (file)
@@ -85,6 +85,11 @@ static int process_file(char const *filename)
                .allow_foreign = true   /* Because we don't know what protocol we're operating with */
        };
 
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
        config = main_config_alloc(NULL);
        if (!config) {
                fprintf(stderr, "Failed allocating main config");
@@ -154,7 +159,14 @@ int main(int argc, char *argv[])
        fr_dict_t               *dict = NULL;
        char const              *receipt_file = NULL;
 
-       TALLOC_CTX              *autofree = talloc_autofree_context();
+       TALLOC_CTX              *autofree;
+
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
 
 #ifndef NDEBUG
        if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
index b6b561d6c51e50d241e33bfe6ca49f991f43487d..6e85b34fe98b1eb1541280c0e06365339288c388 100644 (file)
@@ -693,13 +693,21 @@ int main(int argc, char *argv[])
        fr_dict_t               *dict = NULL;
        char const              *receipt_file = NULL;
 
-       TALLOC_CTX              *autofree = talloc_autofree_context();
-       TALLOC_CTX              *thread_ctx = talloc_new(autofree);
+       TALLOC_CTX              *autofree;
+       TALLOC_CTX              *thread_ctx;
 
        char                    *p;
        main_config_t           *config;
        dl_module_loader_t      *dl_modules = NULL;
 
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
+       thread_ctx = talloc_new(autofree);
+
        config = main_config_alloc(autofree);
        if (!config) {
                fr_perror("unit_test_module");
index ec0565ff03c5a1e5ab48442ee63bbd6cb8bff6ec..e29f202e4f028a0a5e3cb6b11edd4b8146c00d01 100644 (file)
@@ -59,6 +59,7 @@ typedef struct {
 _Thread_local fr_exit_handler_list_t   *thread_local_atexit = NULL;
 static fr_exit_handler_list_t          *global_atexit = NULL;
 static pthread_mutex_t                 global_atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
+static bool                            is_exiting;
 
 
 /** Call the exit handler
@@ -128,9 +129,31 @@ static int _global_list_free(fr_exit_handler_list_t *ehl)
  */
 static void _global_free(void)
 {
+       pthread_mutex_lock(&global_atexit_mutex);
+       fr_cond_assert_msg(!is_exiting, "Global free function called multiple times");
+       is_exiting = true;
+       pthread_mutex_unlock(&global_atexit_mutex);
+
        TALLOC_FREE(global_atexit);
 }
 
+/** Setup the atexit handler, should be called at the start of a program's execution
+ *
+ */
+int fr_thread_local_atexit_setup(void)
+{
+       if (global_atexit) return 0;
+
+       global_atexit = talloc_zero(NULL, fr_exit_handler_list_t);
+       if (unlikely(!global_atexit)) return -1;
+
+       fr_dlist_talloc_init(&global_atexit->head, fr_exit_handler_entry_t, entry);
+       talloc_set_destructor(global_atexit, _global_list_free);
+       atexit(_global_free);   /* Call all remaining destructors at process exit */
+
+       return 0;
+}
+
 /** Add a new destructor
  *
  * @return
@@ -139,20 +162,17 @@ static void _global_free(void)
  */
 int fr_thread_local_atexit(fr_thread_local_atexit_t func, void const *uctx)
 {
+       int ret = 0;
+
        /*
         *      Initialise the global list containing all the thread-local
         *      dlist destructors.
         */
        pthread_mutex_lock(&global_atexit_mutex);
-       if (!global_atexit) {
-               global_atexit = talloc_zero(NULL, fr_exit_handler_list_t);
-               if (unlikely(!global_atexit)) return -1;
-
-               fr_dlist_talloc_init(&global_atexit->head, fr_exit_handler_entry_t, entry);
-               talloc_set_destructor(global_atexit, _global_list_free);
-               atexit(_global_free);   /* Call all remaining destructors at process exit */
-       }
+       fr_cond_assert_msg(!is_exiting, "New atexit handlers should not be allocated whilst exiting");
+       if (!global_atexit) ret = fr_thread_local_atexit_setup();
        pthread_mutex_unlock(&global_atexit_mutex);
+       if (ret < 0) return ret;
 
        /*
         *      Initialise the thread local list, just for pthread_exit().
index cc6fc60050ae05ace5c957feb09af7c8f81f4b46..c3adab351344a8ac6acd490b9d0ec896949aad65 100644 (file)
@@ -38,6 +38,8 @@ extern "C" {
 
 typedef void(*fr_thread_local_atexit_t)(void *uctx);
 
+int fr_thread_local_atexit_setup(void);
+
 int fr_thread_local_atexit(fr_thread_local_atexit_t func, void const *uctx);
 
 /** Set a destructor for thread local storage to free the memory on thread exit
index bf8dcc9e111f62aa93309bf7c3196faf5704f5af..0439e26fa3f82938fde73763801687c49ab0fbad 100644 (file)
@@ -843,7 +843,7 @@ int main(int argc, char **argv)
        char            history_file[PATH_MAX];
 #endif
 
-       TALLOC_CTX      *autofree = talloc_autofree_context();
+       TALLOC_CTX      *autofree;
 
        char *commands[MAX_COMMANDS];
        int num_commands = -1;
@@ -853,6 +853,13 @@ int main(int argc, char **argv)
        char const *prompt = "radmin> ";
        char prompt_buffer[1024];
 
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
+
 #ifndef NDEBUG
        if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
                fr_perror("radmin");
index 976fb0c23b51eea01958d424f56bb89c7866b287..79209baa2652c3dfb97d220e72d3dd2721b7af9e 100644 (file)
@@ -612,10 +612,17 @@ int main(int argc, char **argv)
        RADIUS_PACKET           *packet = NULL;
        RADIUS_PACKET           *reply = NULL;
 
-       TALLOC_CTX              *autofree = talloc_autofree_context();
+       TALLOC_CTX              *autofree;
 
        int                     ret;
 
+       /*
+        *      Must be called first, so the handler is called last
+        */
+       fr_thread_local_atexit_setup();
+
+       autofree = talloc_autofree_context();
+
        fr_debug_lvl = 1;
 
        while ((c = getopt(argc, argv, "d:D:f:hr:t:vxi:")) != -1) switch(c) {