]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Rework dictionary reference counting system
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 6 Apr 2021 23:59:42 +0000 (00:59 +0100)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 7 Apr 2021 00:02:21 +0000 (01:02 +0100)
This lets us know which files are still holding onto dictionary references

18 files changed:
src/bin/fuzzer.c
src/bin/radict.c
src/bin/radiusd.c
src/bin/radsniff.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/server/main_config.c
src/lib/server/virtual_servers.c
src/lib/util/dict.h
src/lib/util/dict_fixup.c
src/lib/util/dict_priv.h
src/lib/util/dict_tokenize.c
src/lib/util/dict_util.c
src/lib/util/pair_legacy_tests.c
src/listen/control/radmin.c
src/modules/proto_ldap_sync/sync_touch.c

index 0273285690937fc04226c38ffac6713ac9dcd0cb..9c2eb50087c9a2907016c9b9deb3e9e99706defb 100644 (file)
@@ -36,19 +36,24 @@ RCSID("$Id$")
  *     ./build/make/jlibtool --mode=execute ./build/bin/local/fuzzer_radius -D share/dictionary /path/to/corpus/directory/
  */
 
-static bool                         init       = false;
-static void *                       decode_ctx = NULL;
-static fr_test_point_proto_decode_t *tp                = NULL;
-static fr_dict_t *                  dict       = NULL;
+static bool                    init = false;
+static void                    *decode_ctx = NULL;
+static fr_test_point_proto_decode_t *tp        = NULL;
+static dl_t                    *dl = NULL;
+static dl_loader_t             *dl_loader;
 
-static dl_t *      dl = NULL;
-static dl_loader_t *dl_loader;
+static fr_dict_t               *dict = NULL;
+static fr_dict_gctx_t const    *dict_gctx = NULL;
 
 int LLVMFuzzerInitialize(int *argc, char ***argv);
 int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len);
 
-static void exitHandler()
+static void exitHandler(void)
 {
+       fr_dict_free(&dict, __FILE__);
+
+       if (fr_dict_global_ctx_free(dict_gctx) < 0) fr_perror("fuzzer");
+
        if (dl && dl->handle) {
                dlclose(dl->handle);
                dl->handle = NULL;
@@ -58,10 +63,10 @@ static void exitHandler()
 
 int LLVMFuzzerInitialize(int *argc, char ***argv)
 {
-       char const *lib_dir  = getenv("FR_LIBRARY_PATH");
-       char const *proto    = getenv("FR_LIBRARY_FUZZ_PROTOCOL");
-       char const *dict_dir = getenv("FR_DICTIONARY_DIR");
-       char        buffer[1024];
+       char const              *lib_dir  = getenv("FR_LIBRARY_PATH");
+       char const              *proto    = getenv("FR_LIBRARY_FUZZ_PROTOCOL");
+       char const              *dict_dir = getenv("FR_DICTIONARY_DIR");
+       char                    buffer[1024];
 
        if (!argc || !argv || !*argv) return -1; /* shut up clang scan */
 
@@ -132,12 +137,13 @@ int LLVMFuzzerInitialize(int *argc, char ***argv)
                fr_exit_now(EXIT_FAILURE);
        }
 
-       if (!fr_dict_global_ctx_init(NULL, dict_dir)) {
+       dict_gctx = fr_dict_global_ctx_init(NULL, dict_dir);
+       if (!dict_gctx) {
                fr_perror("dict_global");
                fr_exit_now(EXIT_FAILURE);
        }
 
-       if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR) < 0) {
+       if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
                fr_perror("fuzzer: Failed initializing internal dictionary");
                fr_exit_now(EXIT_FAILURE);
        }
index 7151a258104da0bd7ae4e020c3889237810d9f1b..544deae62a3d3a96d6a63488f76e6955490720df 100644 (file)
@@ -118,7 +118,7 @@ static int load_dicts(char const *dict_dir)
                                }
 
                                INFO("Loading dictionary: %s/dictionary", file_str);
-                               if (fr_dict_protocol_afrom_file(dict_end, dp->d_name, NULL) < 0) {
+                               if (fr_dict_protocol_afrom_file(dict_end, dp->d_name, NULL, __FILE__) < 0) {
                                        goto error;
                                }
                                dict_end++;
@@ -233,13 +233,14 @@ static void fr_dict_export(uint64_t *count, uintptr_t *low, uintptr_t *high, fr_
  */
 int main(int argc, char *argv[])
 {
-       char const      *dict_dir = DICTDIR;
-       char            c;
-       int             ret = 0;
-       bool            found = false;
-       bool            export = false;
+       char const              *dict_dir = DICTDIR;
+       char                    c;
+       int                     ret = 0;
+       bool                    found = false;
+       bool                    export = false;
 
-       TALLOC_CTX      *autofree;
+       TALLOC_CTX              *autofree;
+       fr_dict_gctx_t const    *our_dict_gctx = NULL;
 
        /*
         *      Must be called first, so the handler is called last
@@ -295,7 +296,8 @@ int main(int argc, char *argv[])
                goto finish;
        }
 
-       if (!fr_dict_global_ctx_init(autofree, dict_dir)) {
+       our_dict_gctx = fr_dict_global_ctx_init(autofree, dict_dir);
+       if (!our_dict_gctx) {
                fr_perror("radict");
                ret = 1;
                goto finish;
@@ -303,7 +305,7 @@ int main(int argc, char *argv[])
 
        INFO("Loading dictionary: %s/%s", dict_dir, FR_DICTIONARY_FILE);
 
-       if (fr_dict_internal_afrom_file(dict_end++, FR_DICTIONARY_INTERNAL_DIR) < 0) {
+       if (fr_dict_internal_afrom_file(dict_end++, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
                fr_perror("radict");
                ret = 1;
                goto finish;
@@ -360,6 +362,18 @@ int main(int argc, char *argv[])
        }
 
 finish:
-       talloc_free(autofree);
+       /*
+        *      Release our references on all the dicts
+        *      we loaded.
+        */
+       {
+               fr_dict_t       **dict_p = dicts;
+
+               do {
+                       fr_dict_free(dict_p, __FILE__);
+               } while (++dict_p < dict_end);
+       }
+       if (fr_dict_global_ctx_free(our_dict_gctx) < 0) fr_perror("radict");
+       if (talloc_free(autofree) < 0) fr_perror("radict");
        return found ? ret : 64;
 }
index 6231c78b80bc2535f08eedf26d722218dcaf0794..cb074666ed7f9d28ad16839c8467459b371d5ffd 100644 (file)
@@ -188,24 +188,26 @@ static void fr_exit_after(fr_event_list_t *el, fr_time_t now, void *uctx)
  */
 int main(int argc, char *argv[])
 {
-       int             status;
-       int             c;
-       bool            display_version = false;
-       bool            radmin = false;
-       int             from_child[2] = {-1, -1};
-       char            *program;
-       fr_schedule_t   *sc = NULL;
-       int             ret = EXIT_SUCCESS;
+       int                     status;
+       int                     c;
+       bool                    display_version = false;
+       bool                    radmin = false;
+       int                     from_child[2] = {-1, -1};
+       char                    *program;
+       fr_schedule_t           *sc = NULL;
+       int                     ret = EXIT_SUCCESS;
 
-       TALLOC_CTX      *global_ctx = NULL;
-       main_config_t   *config = NULL;
-       bool            talloc_memory_report = false;
+       TALLOC_CTX              *global_ctx = NULL;
+       main_config_t           *config = NULL;
+       bool                    talloc_memory_report = false;
 
-       bool            raddb_dir_set = false;
+       bool                    raddb_dir_set = false;
 
-       size_t          pool_size = 0;
-       void            *pool_page_start = NULL, *pool_page_end = NULL;
-       bool            do_mprotect;
+       size_t                  pool_size = 0;
+       void                    *pool_page_start = NULL, *pool_page_end = NULL;
+       bool                    do_mprotect;
+
+       fr_dict_gctx_t const    *dict_gctx = NULL;
 
        dl_module_loader_t *dl_modules = NULL;
 
@@ -514,7 +516,8 @@ int main(int argc, char *argv[])
         *      Initialise the top level dictionary hashes which hold
         *      the protocols.
         */
-       if (!fr_dict_global_ctx_init(global_ctx, config->dict_dir)) {
+       dict_gctx = fr_dict_global_ctx_init(global_ctx, config->dict_dir);
+       if (!dict_gctx) {
                fr_perror("%s", program);
                EXIT_WITH_FAILURE;
        }
@@ -1006,10 +1009,26 @@ cleanup:
         */
        if (dl_modules) talloc_free(dl_modules);
 
+       /*
+        *      Complain in debug builds about dictionaries
+        *      that haven't been freed.
+        */
+       if (fr_dict_global_ctx_free(dict_gctx) < 0) {
+#ifndef NDEBUG
+               fr_perror("radiusd");
+               ret = EXIT_FAILURE;
+#endif
+       }
+
        /*
         *  Cleanup everything else
         */
-       talloc_free(global_ctx);
+       if (talloc_free(global_ctx) < 0) {
+#ifndef NDEBUG
+               fr_perror("radiusd");
+               ret = EXIT_FAILURE;
+#endif
+       }
 
        /*
         *  Anything not cleaned up by the above is allocated in
index 641f2fe9acfc524c76dfb6eba5737a82f68920ce..acd10c18760a95d1e12c5518df9bbbe6590ff2f9 100644 (file)
@@ -2245,21 +2245,22 @@ static NEVER_RETURNS void usage(int status)
  */
 int main(int argc, char *argv[])
 {
-       fr_pcap_t       *in = NULL, *in_p;
-       fr_pcap_t       **in_head = &in;
-       fr_pcap_t       *out = NULL;
+       fr_pcap_t               *in = NULL, *in_p;
+       fr_pcap_t               **in_head = &in;
+       fr_pcap_t               *out = NULL;
 
-       int             ret = EXIT_SUCCESS;                             /* Exit status */
+       int                     ret = EXIT_SUCCESS;                             /* Exit status */
 
-       char            errbuf[PCAP_ERRBUF_SIZE];                       /* Error buffer */
-       int             port = FR_AUTH_UDP_PORT;
+       char                    errbuf[PCAP_ERRBUF_SIZE];                       /* Error buffer */
+       int                     port = FR_AUTH_UDP_PORT;
 
-       int             c;
-       char const      *raddb_dir = RADDBDIR;
-       char const      *dict_dir = DICTDIR;
-       TALLOC_CTX      *autofree;
+       int                     c;
+       char const              *raddb_dir = RADDBDIR;
+       char const              *dict_dir = DICTDIR;
+       TALLOC_CTX              *autofree;
+       fr_dict_gctx_t const    *dict_gctx = NULL;
 
-       rs_stats_t      *stats;
+       rs_stats_t              *stats;
 
        fr_debug_lvl = 1;
        fr_log_fp = stdout;
@@ -2608,7 +2609,8 @@ int main(int argc, char *argv[])
                                                         conf->pcap_filter, conf->pcap_filter);
        }
 
-       if (!fr_dict_global_ctx_init(conf, dict_dir)) {
+       dict_gctx = fr_dict_global_ctx_init(conf, dict_dir);
+       if (!dict_gctx) {
                fr_perror("radsniff");
                fr_exit_now(EXIT_FAILURE);
        }
@@ -3048,5 +3050,10 @@ finish:
        fr_dict_autofree(radsniff_dict);
        fr_radius_free();
 
+       if (fr_dict_global_ctx_free(dict_gctx) < 0) {
+               fr_perror("radsniff");
+               ret = EXIT_FAILURE;
+       }
+
        return ret;
 }
index 11d69a8d6e8a14718024f13e42cf75b6c1c5206b..9bdd53faf6d49cef46db0149c99e3e15b6f3704c 100644 (file)
@@ -198,9 +198,11 @@ int main(int argc, char **argv)
        int                     zap = 0;
        fr_dict_t               *dict = NULL;
        TALLOC_CTX              *autofree;
+       fr_dict_gctx_t const    *dict_gctx = NULL;
 
        char const              *p;
        main_config_t           *config;
+       int                     ret = EXIT_SUCCESS;
 
        /*
         *      Must be called first, so the handler is called last
@@ -305,13 +307,14 @@ int main(int argc, char **argv)
                return 1;
        }
 
-       if (!fr_dict_global_ctx_init(autofree, config->dict_dir)) {
+       dict_gctx = fr_dict_global_ctx_init(autofree, config->dict_dir);
+       if (!dict_gctx) {
                fr_perror("%s", main_config->name);
                fr_exit_now(EXIT_FAILURE);
        }
 
 
-       if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR) < 0) {
+       if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
                fr_perror("%s", config->name);
                fr_exit_now(EXIT_FAILURE);
        }
@@ -560,7 +563,11 @@ int main(int argc, char **argv)
        }
        fclose(fp);
 
+       if (fr_dict_global_ctx_free(dict_gctx) < 0) {
+               fr_perror("radwho");
+               ret = EXIT_FAILURE;
+       }
        main_config_free(&config);
 
-       return 0;
+       return ret;
 }
index 0333bde11f517ca1577a299185e0a5b817e2017e..037607425936d9855b587b8f4321d81f2961e622 100644 (file)
@@ -912,7 +912,9 @@ static int dictionary_load_common(command_result_t *result, command_file_ctx_t *
        /*
         *      Decrease ref count if we're loading in a new dictionary
         */
-       if (cc->tmpl_rules.dict_def) fr_dict_const_free(&cc->tmpl_rules.dict_def);
+       if (cc->tmpl_rules.dict_def) {
+               if (fr_dict_const_free(&cc->tmpl_rules.dict_def, __FILE__) < 0) return -1;
+       }
 
        q = strchr(in, ' ');
        if (q) {
@@ -924,7 +926,7 @@ static int dictionary_load_common(command_result_t *result, command_file_ctx_t *
                dir = default_subdir;
        }
 
-       ret = fr_dict_protocol_afrom_file(&dict, name, dir);
+       ret = fr_dict_protocol_afrom_file(&dict, name, dir, __FILE__);
        talloc_free(tmp);
        if (ret < 0) RETURN_COMMAND_ERROR();
 
@@ -2620,7 +2622,10 @@ size_t process_line(command_result_t *result, command_file_ctx_t *cc, char *data
 
 static int _command_ctx_free(command_file_ctx_t *cc)
 {
-       fr_dict_free(&cc->test_internal_dict);
+       if (fr_dict_free(&cc->test_internal_dict, __FILE__) < 0) {
+               fr_perror("unit_test_attribute");
+               return -1;
+       }
        return 0;
 }
 
@@ -2662,7 +2667,7 @@ static command_file_ctx_t *command_ctx_alloc(TALLOC_CTX *ctx,
        }
 
        fr_dict_global_ctx_set(cc->test_gctx);
-       if (fr_dict_internal_afrom_file(&cc->test_internal_dict, FR_DICTIONARY_INTERNAL_DIR) < 0) {
+       if (fr_dict_internal_afrom_file(&cc->test_internal_dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
                fr_perror("Failed loading test dict_gctx internal dictionary");
                return NULL;
        }
@@ -2829,7 +2834,11 @@ finish:
        /*
         *      Free any residual resources we loaded.
         */
-       if (cc) fr_dict_const_free(&cc->tmpl_rules.dict_def);
+       if (cc && (fr_dict_const_free(&cc->tmpl_rules.dict_def, __FILE__) < 0)) {
+               fr_perror("unit_test_attribute");
+               ret = -1;
+       }
+
        fr_dict_global_ctx_set(config->dict_gctx);      /* Switch back to the main dict ctx */
        unload_proto_library();
        talloc_free(cc);
@@ -3114,7 +3123,7 @@ int main(int argc, char *argv[])
                EXIT_WITH_FAILURE;
        }
 
-       if (fr_dict_internal_afrom_file(&config.dict, FR_DICTIONARY_INTERNAL_DIR) < 0) {
+       if (fr_dict_internal_afrom_file(&config.dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
                fr_perror("unit_test_attribute");
                EXIT_WITH_FAILURE;
        }
@@ -3220,7 +3229,10 @@ cleanup:
        if (talloc_free(dl_loader) < 0) {
                fr_perror("unit_test_attribute - dl_loader - ");        /* Print free order issues */
        }
-       fr_dict_free(&config.dict);
+       if (fr_dict_free(&config.dict, __FILE__) < 0) {
+               fr_perror("unit_test_attribute");
+               ret = EXIT_FAILURE;
+       }
 
        unlang_free_global();
 
@@ -3230,6 +3242,7 @@ cleanup:
         */
        if (fr_dict_global_ctx_free(config.dict_gctx) < 0) {
                fr_perror("unit_test_attribute");       /* Print free order issues */
+               ret = EXIT_FAILURE;
        }
 
        if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) {
@@ -3241,7 +3254,10 @@ cleanup:
         *      Explicitly free the autofree context
         *      to make errors less confusing.
         */
-       talloc_free(autofree);
+       if (talloc_free(autofree) < 0) {
+               fr_perror("unit_test_attribute");
+               ret = EXIT_FAILURE;
+       }
 
        return ret;
 }
index cb5f3f14d555d019510650af9884741dd127f95b..31525fa42dc05985d4a72d055eb4845b89c1850f 100644 (file)
@@ -165,6 +165,7 @@ int main(int argc, char *argv[])
        char const              *receipt_file = NULL;
 
        TALLOC_CTX              *autofree;
+       fr_dict_gctx_t const    *dict_gctx = NULL;
 
        /*
         *      Must be called first, so the handler is called last
@@ -233,12 +234,13 @@ int main(int argc, char *argv[])
                EXIT_WITH_FAILURE;
        }
 
-       if (!fr_dict_global_ctx_init(autofree, dict_dir)) {
+       dict_gctx = fr_dict_global_ctx_init(autofree, dict_dir);
+       if (!dict_gctx) {
                fr_perror("unit_test_map");
                EXIT_WITH_FAILURE;
        }
 
-       if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR) < 0) {
+       if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
                fr_perror("unit_test_map");
                EXIT_WITH_FAILURE;
        }
@@ -276,9 +278,20 @@ cleanup:
        /*
         *      Free any autoload dictionaries
         */
-       fr_dict_autofree(unit_test_module_dict);
+       if (fr_dict_autofree(unit_test_module_dict) < 0) {
+               fr_perror("unit_test_map");
+               ret = EXIT_FAILURE;
+       }
+
+       if (fr_dict_free(&dict, __FILE__) < 0) {
+               fr_perror("unit_test_map");
+               ret = EXIT_FAILURE;
+       }
 
-       fr_dict_free(&dict);
+       if (fr_dict_global_ctx_free(dict_gctx) < 0) {
+               fr_perror("unit_test_map");
+               ret = EXIT_FAILURE;
+       }
 
        if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) {
                fr_perror("unit_test_map");
index 38a9ed591c559eae7f8f2eca08bb8737862233e4..d40c0c68eb8fa64c69b3c8c870c55068e661d216 100644 (file)
@@ -490,7 +490,7 @@ int main(int argc, char *argv[])
        const char              *output_file = NULL;
        const char              *filter_file = NULL;
        FILE                    *fp;
-       request_t                       *request = NULL;
+       request_t               *request = NULL;
        fr_pair_t               *vp;
        fr_pair_list_t          filter_vps;
        bool                    xlat_only = false;
@@ -501,6 +501,7 @@ int main(int argc, char *argv[])
        char const              *receipt_file = NULL;
 
        TALLOC_CTX              *autofree;
+       fr_dict_gctx_t const    *dict_gctx = NULL;
        TALLOC_CTX              *thread_ctx;
 
        char                    *p;
@@ -680,12 +681,13 @@ int main(int argc, char *argv[])
                EXIT_WITH_FAILURE;
        }
 
-       if (!fr_dict_global_ctx_init(autofree, config->dict_dir)) {
+       dict_gctx = fr_dict_global_ctx_init(autofree, config->dict_dir);
+       if (!dict_gctx) {
                fr_perror("%s", config->name);
                EXIT_WITH_FAILURE;
        }
 
-       if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR) < 0) {
+       if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
                fr_perror("%s", config->name);
                EXIT_WITH_FAILURE;
        }
@@ -975,15 +977,37 @@ cleanup:
        /*
         *      Free our explicitly loaded internal dictionary
         */
-       fr_dict_free(&dict);
+       if (fr_dict_free(&dict, __FILE__) < 0) {
+               fr_perror("unit_test_module");
+               ret = EXIT_FAILURE;
+       }
 
        if (dl_modules) talloc_free(dl_modules);
 
+       /*
+        *      Free any openssl resources and the TLS dictionary
+        */
+       fr_openssl_free();
+
+       /*
+        *      Free all the dictionaries, and complain/fail if
+        *      they still have dependents.
+        */
+       if (fr_dict_global_ctx_free(dict_gctx) < 0) {
+               fr_perror("unit_test_module");
+               ret = EXIT_FAILURE;
+       }
+
        if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) {
                fr_perror("unit_test_module");
                ret = EXIT_FAILURE;
        }
 
+       if (talloc_free(autofree) < 0) {
+               fr_perror("unit_test_module");
+               ret = EXIT_FAILURE;
+       }
+
        return ret;
 }
 
index 8c5c569ba90b944cd5bf6b2f962da6643014ae78..92e31852269872a5720e9319b578e0317dd9254b 100644 (file)
@@ -906,7 +906,7 @@ int main_config_init(main_config_t *config)
         */
        config->talloc_pool_size = 8 * 1024; /* default */
 
-       if (fr_dict_internal_afrom_file(&config->dict, FR_DICTIONARY_INTERNAL_DIR) < 0) {
+       if (fr_dict_internal_afrom_file(&config->dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
                PERROR("Failed reading internal dictionaries");
                goto failure;
        }
@@ -1242,7 +1242,7 @@ int main_config_free(main_config_t **config)
         *      Frees current config and any previous configs.
         */
        TALLOC_FREE((*config)->root_cs);
-       talloc_decrease_ref_count((*config)->dict);
+       fr_dict_free(&(*config)->dict, __FILE__);
        TALLOC_FREE(*config);
 
        return 0;
index 19287fda953940f8aa0e1235cfb4f8a7bc24a57c..6c2bb7e586a8ba9806d7f32867e9ddc68cd2da98 100644 (file)
@@ -161,8 +161,8 @@ const CONF_PARSER virtual_servers_config[] = {
 };
 
 typedef struct {
-       bool    do_free;
-       fr_dict_t const *dict;
+       fr_dict_t const         *dict;
+       char const              *server;
 } virtual_server_dict_t;
 
 /** Decrement references on dictionaries as the config sections are freed
@@ -170,16 +170,12 @@ typedef struct {
  */
 static int _virtual_server_dict_free(virtual_server_dict_t *cd)
 {
-       if (cd->do_free) {
-               fr_dict_t *dict;
-               memcpy(&dict, &cd->dict, sizeof(dict));
-               fr_dict_free(&dict);
-       }
+       fr_dict_const_free(&cd->dict, cd->server);
        return 0;
 }
 
 
-void virtual_server_dict_set(CONF_SECTION *server_cs, fr_dict_t const *dict, bool do_free)
+void virtual_server_dict_set(CONF_SECTION *server_cs, fr_dict_t const *dict, bool reference)
 {
        virtual_server_dict_t *p;
        CONF_DATA const *cd;
@@ -194,12 +190,13 @@ void virtual_server_dict_set(CONF_SECTION *server_cs, fr_dict_t const *dict, boo
                return;
        }
 
-       fr_dict_reference(fr_dict_unconst(dict));
        p = talloc_zero(server_cs, virtual_server_dict_t);
-       p->do_free = do_free;
        p->dict = dict;
+       p->server = talloc_strdup(p, cf_section_name2(server_cs));
        talloc_set_destructor(p, _virtual_server_dict_free);
 
+       if (reference) fr_dict_dependent_add(fr_dict_unconst(dict), p->server);
+
        cf_data_add(server_cs, p, "dictionary", true);
 }
 
@@ -268,13 +265,13 @@ static int namespace_on_read(TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *par
        /*
         *      @todo - print out the entire error stack?
         */
-       if (fr_dict_protocol_afrom_file(&dict, file, dir) < 0) {
+       if (fr_dict_protocol_afrom_file(&dict, file, dir, cf_section_name2(server_cs)) < 0) {
                cf_log_perr(ci, "Failed loading namespace '%s'", namespace);
                return -1;
        }
 
 set:
-       virtual_server_dict_set(server_cs, dict, true);
+       virtual_server_dict_set(server_cs, dict, false);
 
        module_name = talloc_strdup(ctx, namespace);
 
@@ -371,7 +368,7 @@ static int listen_on_read(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void
        if (!set_dict) return 0;
 
        app = (fr_app_t const *) module->common;
-       if (app->dict) virtual_server_dict_set(server_cs, *app->dict, false);
+       if (app->dict) virtual_server_dict_set(server_cs, *app->dict, true);
 
        return 0;
 }
index b57c294c8b9b60aefba9818df67645c3e397a224..c621dcdb06bd7aa756b866a1b48416ee28528768 100644 (file)
@@ -551,9 +551,11 @@ fr_dict_enum_t             *fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name
  *
  * @{
  */
-int                    fr_dict_internal_afrom_file(fr_dict_t **out, char const *internal_name);
+int                    fr_dict_internal_afrom_file(fr_dict_t **out, char const *internal_name,
+                                                   char const *dependent);
 
-int                    fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char const *proto_dir);
+int                    fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char const *proto_dir,
+                                                   char const *dependent);
 
 int                    fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename);
 /** @} */
@@ -566,9 +568,11 @@ int                        fr_dict_enum_autoload(fr_dict_enum_autoload_t const *to_load);
 
 int                    fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load);
 
-int                    fr_dict_autoload(fr_dict_autoload_t const *to_load);
+#define                        fr_dict_autoload(_to_load) _fr_dict_autoload(_to_load, __FILE__)
+int                    _fr_dict_autoload(fr_dict_autoload_t const *to_load, char const *dependent);
 
-void                   fr_dict_autofree(fr_dict_autoload_t const *to_free);
+#define                        fr_dict_autofree(_to_free) _fr_dict_autofree(_to_free, __FILE__)
+int                    _fr_dict_autofree(fr_dict_autoload_t const *to_free, char const *dependent);
 
 int                    fr_dl_dict_enum_autoload(dl_t const *module, void *symbol, void *user_ctx);
 
@@ -585,11 +589,11 @@ void                      fr_dl_dict_autofree(dl_t const *module, void *symbol, void *user_ctx);
  */
 fr_dict_t              *fr_dict_alloc(char const *proto_name, unsigned int proto_number) CC_HINT(nonnull);
 
-void                   fr_dict_reference(fr_dict_t *dict);
+void                   fr_dict_dependent_add(fr_dict_t *dict, char const *dependent) CC_HINT(nonnull);
 
-int                    fr_dict_free(fr_dict_t **dict);
+int                    fr_dict_free(fr_dict_t **dict, char const *dependent) CC_HINT(nonnull);
 
-int                    fr_dict_const_free(fr_dict_t const **dict);
+int                    fr_dict_const_free(fr_dict_t const **dict, char const *dependent) CC_HINT(nonnull);
 /** @} */
 
 /** @name Global dictionary management
index 33514cc8c6b77aa163c094952ac6042d9403e70a..7bab1076de6f6cb6f556ef053688ef49f7478212 100644 (file)
@@ -249,7 +249,7 @@ static fr_dict_attr_t const *dict_find_or_load_reference(fr_dict_t **dict_def, c
 
                if (p) *p = '\0';
 
-               if (fr_dict_protocol_afrom_file(&other, ref, NULL) < 0) {
+               if (fr_dict_protocol_afrom_file(&other, ref, NULL, filename) < 0) {
                        return NULL;
                }
 
index ee7fe1007490f6f4cb6209168cb274cc006590e1..dd0e23affb54608519fba311023deb7ec959fe48 100644 (file)
@@ -52,6 +52,15 @@ extern "C" {
                } \
        } while (0)
 
+/** Entry recording dictionary reference holders by file
+ */
+typedef struct {
+       fr_rb_node_t            node;
+       int                     count;                  //!< How many references are held by this file.
+                                                       ///< Signed to help figure out when things go wrong...
+       char const              *dependent;             //!< File holding the reference.
+} fr_dict_dependent_t;
+
 /** Vendors and attribute names
  *
  * It's very likely that the same vendors will operate in multiple
@@ -96,6 +105,8 @@ struct fr_dict {
        fr_dict_attr_valid_func_t attr_valid;           //!< validation function for new attributes
 
        fr_dict_attr_t          **fixups;               //!< Attributes that need fixing up.
+
+       rbtree_t                *dependents;            //!< Which files are using this dictionary.
 };
 
 struct fr_dict_gctx_s {
@@ -126,6 +137,12 @@ extern fr_dict_gctx_t *dict_gctx;
 extern fr_table_num_ordered_t const    date_precision_table[];
 extern size_t                          date_precision_table_len;
 
+bool                   dict_has_dependents(fr_dict_t *dict);
+
+int                    dict_dependent_add(fr_dict_t *dict, char const *dependent);
+
+int                    dict_dependent_remove(fr_dict_t *dict, char const *dependent);
+
 fr_dict_t              *dict_alloc(TALLOC_CTX *ctx);
 
 int                    dict_dlopen(fr_dict_t *dict, char const *name);
index d7f4914deb7b4f185466fef4ff5f71e4973626be..9aa4ccdf781fdd58d3b79f8a9dd5708b0f469f5e 100644 (file)
@@ -1460,7 +1460,7 @@ post_option:
                return 0;
        }
 
-       dict = dict_alloc(NULL);
+       dict = dict_alloc(dict_gctx);
 
        /*
         *      Try to load protocol-specific validation routines.
@@ -2309,11 +2309,12 @@ static int dict_from_file(fr_dict_t *dict,
  *
  * @param[out] out             Where to write pointer to the internal dictionary.
  * @param[in] dict_subdir      name of the internal dictionary dir (may be NULL).
+ * @param[in] dependent                Either C src file, or another dictionary.
  * @return
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir)
+int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent)
 {
        fr_dict_t               *dict;
        char                    *dict_path = NULL;
@@ -2330,7 +2331,7 @@ int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir)
         *      Increase the reference count of the internal dictionary.
         */
        if (dict_gctx->internal) {
-                talloc_increase_ref_count(dict_gctx->internal);
+                dict_dependent_add(dict_gctx->internal, dependent);
                 *out = dict_gctx->internal;
                 return 0;
        }
@@ -2393,8 +2394,14 @@ int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir)
 
        talloc_free(dict_path);
 
+       dict_dependent_add(dict, dependent);
+
+       if (!dict_gctx->internal) {
+               dict_gctx->internal = dict;
+               dict_dependent_add(dict, "global");
+       }
+
        *out = dict;
-       if (!dict_gctx->internal) dict_gctx->internal = dict;
 
        return 0;
 }
@@ -2407,11 +2414,12 @@ int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir)
  *                             dictionary if files have changed and *out is not NULL.
  * @param[in] proto_name       that we're loading the dictionary for.
  * @param[in] proto_dir                Explicitly set where to hunt for the dictionary files.  May be NULL.
+ * @param[in] dependent                Either C src file, or another dictionary.
  * @return
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char const *proto_dir)
+int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char const *proto_dir, char const *dependent)
 {
        char            *dict_dir = NULL;
        fr_dict_t       *dict;
@@ -2434,7 +2442,7 @@ int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char co
         */
        dict = dict_by_protocol_name(proto_name);
        if (dict && dict->autoloaded) {
-               talloc_increase_ref_count(dict);
+                dict_dependent_add(dict, dependent);
                *out = dict;
                return 0;
        }
@@ -2475,10 +2483,9 @@ int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char co
         *      If we're autoloading a previously defined dictionary,
         *      then mark up the dictionary as now autoloaded.
         */
-       if (!dict->autoloaded) {
-//             talloc_increase_ref_count(dict);
-               dict->autoloaded = true;
-       }
+       if (!dict->autoloaded) dict->autoloaded = true;
+
+       dict_dependent_add(dict, dependent);
 
        *out = dict;
 
index 6024883fafe751643b5a67096ebee6d7b8ccfc45..4ed1e8acb3987494a1c7f99324d8b9caf1d2d4a8 100644 (file)
@@ -741,6 +741,8 @@ int dict_protocol_add(fr_dict_t *dict)
        }
        dict->in_protocol_by_num = true;
 
+       dict_dependent_add(dict, "global");
+
        return 0;
 }
 
@@ -2721,25 +2723,140 @@ int dict_dlopen(fr_dict_t *dict, char const *name)
        return 0;
 }
 
-static int _dict_free_autoref(void *data, UNUSED void *uctx)
+static int _dict_free_autoref(void *data, void *uctx)
 {
+       fr_dict_t *referer = talloc_get_type_abort(uctx, fr_dict_t);
        fr_dict_t *dict = talloc_get_type_abort(data, fr_dict_t);
 
-       (void)fr_dict_free(&dict);
+       if (fr_dict_free(&dict, referer->root->name) < 0) return -1;
 
        return 0;
 }
 
+/** Find a dependent in the tree of dependents
+ *
+ */
+static int _dict_dependent_cmp(void const *a, void const *b)
+{
+       fr_dict_dependent_t const *dep_a = a;
+       fr_dict_dependent_t const *dep_b = b;
+
+       return strcmp(dep_a->dependent, dep_b->dependent);
+}
+
+/** Record a new dependency on a dictionary
+ *
+ * These are used to determine what is currently depending on a dictionary.
+ *
+ * @param[in] dict     to record dependency on.
+ * @param[in] dependent        Either C src file, or another dictionary.
+ * @return
+ *     - 0 on success.
+ *      - -1 on failure.
+ */
+int dict_dependent_add(fr_dict_t *dict, char const *dependent)
+{
+       fr_dict_dependent_t *found;
+
+       found = rbtree_find(dict->dependents, &(fr_dict_dependent_t){ .dependent = dependent } );
+       if (!found) {
+               fr_dict_dependent_t *new;
+
+               new = talloc_zero(dict->dependents, fr_dict_dependent_t);
+               if (unlikely(!new)) return -1;
+
+               /*
+                *      If the dependent is in a module that gets
+                *      unloaded, any strings in the text area also
+                *      get unloaded (including dependent locations).
+                *
+                *      Strdup the string here so we don't get
+                *      random segfaults if a module forgets to unload
+                *      a dictionary.
+                */
+               new->dependent = talloc_typed_strdup(new, dependent);
+               rbtree_insert(dict->dependents, new);
+
+               new->count = 1;
+
+               return 0;
+       }
+
+       found->count++; /* Increase ref count */
+
+       return 0;
+}
+
+/** Decrement ref count for a dependent in a dictionary
+ *
+ * @param[in] dict     to remove dependency from.
+ * @param[in] dependent        Either C src, or another dictionary dependent.
+ *                     What depends on this dictionary.
+ */
+int dict_dependent_remove(fr_dict_t *dict, char const *dependent)
+{
+       fr_dict_dependent_t *found;
+
+       found = rbtree_find(dict->dependents, &(fr_dict_dependent_t){ .dependent = dependent } );
+       if (!found) {
+               fr_strerror_printf("Dependent \"%s\" not found in dictionary \"%s\"", dependent, dict->root->name);
+               return -1;
+       }
+
+       if (found->count == 0) {
+               fr_strerror_printf("Zero ref count invalid for dependent \"%s\", dictionary \"%s\"",
+                                  dependent, dict->root->name);
+               return -1;
+       }
+
+       if (--found->count == 0) {
+               rbtree_delete(dict->dependents, found);
+               talloc_free(found);
+               return 0;
+       }
+
+       return 1;
+}
+
+/** Check if a dictionary still has dependents
+ *
+ * @param[in] dict     to check
+ * @return
+ *     - true if there's still at least one dependent.
+ *     - false if there are no dependents.
+ */
+bool dict_has_dependents(fr_dict_t *dict)
+{
+       return (rbtree_num_elements(dict->dependents) > 0);
+}
+
 static int _dict_free(fr_dict_t *dict)
 {
        if (!fr_cond_assert(!dict->in_protocol_by_name || fr_hash_table_delete(dict->gctx->protocol_by_name, dict))) {
                fr_strerror_printf("Failed removing dictionary from protocol hash \"%s\"", dict->root->name);
                return -1;
        }
+       dict->in_protocol_by_name = false;
+
        if (!fr_cond_assert(!dict->in_protocol_by_num || fr_hash_table_delete(dict->gctx->protocol_by_num, dict))) {
                fr_strerror_printf("Failed removing dictionary from protocol number_hash \"%s\"", dict->root->name);
                return -1;
        }
+       dict->in_protocol_by_num = false;
+
+       if (dict_has_dependents(dict)) {
+               fr_rb_tree_iter_inorder_t       iter;
+               fr_dict_dependent_t             *dep;
+
+               fr_strerror_printf("Refusing to free dictionary \"%s\", still has dependents", dict->root->name);
+
+               for (dep = rbtree_iter_init_inorder(&iter, dict->dependents);
+                    dep;
+                    dep = rbtree_iter_next_inorder(&iter)) {
+                       fr_strerror_printf_push("%s (%u)", dep->dependent, dep->count);
+               }
+               return -1;
+       }
 
        /*
         *      Free the hash tables with free functions first
@@ -2749,7 +2866,7 @@ static int _dict_free(fr_dict_t *dict)
        talloc_free(dict->vendors_by_name);
 
        if (dict->autoref &&
-           (fr_hash_table_walk(dict->autoref, _dict_free_autoref, NULL) < 0)) {
+           (fr_hash_table_walk(dict->autoref, _dict_free_autoref, dict) < 0)) {
                return -1;
        }
 
@@ -2833,6 +2950,11 @@ fr_dict_t *dict_alloc(TALLOC_CTX *ctx)
                goto error;
        }
 
+       /*
+        *      Who/what depends on this dictionary
+        */
+       dict->dependents = rbtree_alloc(dict, fr_dict_dependent_t, node, _dict_dependent_cmp, NULL, 0);
+
        /*
         *      Set default type size and length.
         */
@@ -2849,46 +2971,69 @@ fr_dict_t *dict_alloc(TALLOC_CTX *ctx)
  *
  * @param[in] dict     to increase the reference count for.
  */
-void fr_dict_reference(fr_dict_t *dict)
+void fr_dict_dependent_add(fr_dict_t *dict, char const *dependent)
 {
-       talloc_increase_ref_count(dict);
+       dict_dependent_add(dict, dependent);
 }
 
 /** Decrement the reference count on a previously loaded dictionary
  *
  * @param[in] dict     to free.
- * @return how many references to the dictionary remain.
+ * @param[in] dependent        that originally allocated this dictionary.
+ * @return
+ *     - 0 on success (dictionary freed).
+ *     - 1 if other things still depend on the dictionary.
+ *     - -1 on error (dependent doesn't exist)
  */
-int fr_dict_free(fr_dict_t **dict)
+int fr_dict_const_free(fr_dict_t const **dict, char const *dependent)
 {
-       int ret;
+       fr_dict_t **our_dict = UNCONST(fr_dict_t **, dict);
 
-       if (!*dict) return 0;
+       if (!*our_dict) return 0;
 
-       ret = talloc_decrease_ref_count(*dict);
-       *dict = NULL;
+       switch (dict_dependent_remove(*our_dict, dependent)) {
+       case 0:         /* dependent has no more refs */
+               if (!dict_has_dependents(*our_dict)) {
+                       talloc_free(*our_dict);
+                       return 0;
+               }
+               FALL_THROUGH;
 
-       return ret;
+       case 1:         /* dependent has more refs */
+               return 1;
+
+       default:        /* error */
+               return -1;
+       }
 }
 
 /** Decrement the reference count on a previously loaded dictionary
  *
  * @param[in] dict     to free.
- * @return how many references to the dictionary remain.
+ * @param[in] dependent        that originally allocated this dictionary.
+ * @return
+ *     - 0 on success (dictionary freed).
+ *     - 1 if other things still depend on the dictionary.
+ *     - -1 on error (dependent doesn't exist)
  */
-int fr_dict_const_free(fr_dict_t const **dict)
+int fr_dict_free(fr_dict_t **dict, char const *dependent)
 {
-       int ret;
-       fr_dict_t *our_dict;
-
        if (!*dict) return 0;
 
-       memcpy(&our_dict, dict, sizeof(our_dict));
+       switch (dict_dependent_remove(*dict, dependent)) {
+       case 0:         /* dependent has no more refs */
+               if (!dict_has_dependents(*dict)) {
+                       talloc_free(*dict);
+                       return 0;
+               }
+               FALL_THROUGH;
 
-       ret = talloc_decrease_ref_count(our_dict);
-       *dict = NULL;
+       case 1:         /* dependent has more refs */
+               return 1;
 
-       return ret;
+       default:        /* error */
+               return -1;
+       }
 }
 
 /** Process a dict_attr_autoload element to load/verify a dictionary attribute
@@ -2983,7 +3128,7 @@ int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_dict_autoload(fr_dict_autoload_t const *to_load)
+int _fr_dict_autoload(fr_dict_autoload_t const *to_load, char const *dependent)
 {
        fr_dict_autoload_t const        *p;
 
@@ -2999,9 +3144,9 @@ int fr_dict_autoload(fr_dict_autoload_t const *to_load)
                 *      Load the internal dictionary
                 */
                if (strcmp(p->proto, "freeradius") == 0) {
-                       if (fr_dict_internal_afrom_file(&dict, p->proto) < 0) return -1;
+                       if (fr_dict_internal_afrom_file(&dict, p->proto, dependent) < 0) return -1;
                } else {
-                       if (fr_dict_protocol_afrom_file(&dict, p->proto, p->base_dir) < 0) return -1;
+                       if (fr_dict_protocol_afrom_file(&dict, p->proto, p->base_dir, dependent) < 0) return -1;
                }
 
                *(p->out) = dict;
@@ -3015,17 +3160,21 @@ int fr_dict_autoload(fr_dict_autoload_t const *to_load)
  *
  * @param[in] to_free  previously loaded dictionary to free.
  */
-void fr_dict_autofree(fr_dict_autoload_t const *to_free)
+int _fr_dict_autofree(fr_dict_autoload_t const *to_free, char const *dependent)
 {
-       fr_dict_t                       **dict;
-       fr_dict_autoload_t const        *p;
+       fr_dict_autoload_t const *p;
 
        for (p = to_free; p->out; p++) {
-               memcpy(&dict, &p->out, sizeof(dict)); /* const issues */
-               if (!*dict) continue;
+               int ret;
 
-               if (fr_dict_free(dict) == 0) *dict = NULL;
+               if (!*p->out) continue;
+               ret = fr_dict_const_free(p->out, dependent);
+
+               if (ret == 0) *p->out = NULL;
+               if (ret < 0) return -1;
        }
+
+       return 0;
 }
 
 /** Callback to automatically resolve enum values
@@ -3129,17 +3278,18 @@ static int _dict_global_free(fr_dict_gctx_t *gctx)
        bool            still_loaded = false;
 
        if (gctx->internal) {
-               fr_strerror_const("Refusing to free dict gctx.  Internal dictionary is still loaded");
-               still_loaded = true;
+               dict_dependent_remove(gctx->internal, "global");        /* remove our dependency */
+
+               if (talloc_free(gctx->internal) < 0) still_loaded = true;
        }
 
        for (dict = fr_hash_table_iter_init(gctx->protocol_by_name, &iter);
             dict;
             dict = fr_hash_table_iter_next(gctx->protocol_by_name, &iter)) {
                (void)talloc_get_type_abort(dict, fr_dict_t);
-               fr_strerror_printf_push("Refusing to free dict gctx.  %s protocol dictionary is still loaded",
-                                       dict->root->name);
-               still_loaded = true;
+               dict_dependent_remove(dict, "global");                  /* remove our dependency */
+
+               if (talloc_free(dict) < 0) still_loaded = true;
        }
 
        if (still_loaded) return -1;
@@ -3288,8 +3438,10 @@ void fr_dict_global_ctx_read_only(void)
  */
 void fr_dict_global_ctx_debug(void)
 {
-       fr_hash_iter_t  iter;
-       fr_dict_t       *dict;
+       fr_hash_iter_t                  dict_iter;
+       fr_dict_t                       *dict;
+       fr_rb_tree_iter_inorder_t       dep_iter;
+       fr_dict_dependent_t             *dep;
 
        if (!dict_gctx) {
                FR_FAULT_LOG("gctx not initialised");
@@ -3297,14 +3449,23 @@ void fr_dict_global_ctx_debug(void)
        }
 
        FR_FAULT_LOG("gctx %p report", dict_gctx);
-       for (dict = fr_hash_table_iter_init(dict_gctx->protocol_by_num, &iter);
+       for (dict = fr_hash_table_iter_init(dict_gctx->protocol_by_num, &dict_iter);
             dict;
-            dict = fr_hash_table_iter_next(dict_gctx->protocol_by_num, &iter)) {
-               FR_FAULT_LOG("\t%s refs %zu", dict->root->name, talloc_reference_count(dict));
+            dict = fr_hash_table_iter_next(dict_gctx->protocol_by_num, &dict_iter)) {
+               for (dep = rbtree_iter_init_inorder(&dep_iter, dict->dependents);
+                    dep;
+                    dep = rbtree_iter_next_inorder(&dep_iter)) {
+                       FR_FAULT_LOG("\t%s refs %s (%u)", dict->root->name, dep->dependent, dep->count);
+               }
        }
 
-       if (dict_gctx->internal) FR_FAULT_LOG("\t%s refs %zu", dict_gctx->internal->root->name,
-                                             talloc_reference_count(dict_gctx->internal));
+       if (dict_gctx->internal) {
+               for (dep = rbtree_iter_init_inorder(&dep_iter, dict_gctx->internal->dependents);
+                    dep;
+                    dep = rbtree_iter_next_inorder(&dep_iter)) {
+                       FR_FAULT_LOG("\t%s refs %s (%u)", dict_gctx->internal->root->name, dep->dependent, dep->count);
+               }
+       }
 }
 
 /** Coerce to non-const
index dd1878c1157c8631990936f2696e72e048255460..16fe3e8058282dae0615d9a059edd8212dcd15d5 100644 (file)
@@ -179,7 +179,7 @@ static void pair_tests_init(void)
 
        if (!fr_dict_global_ctx_init(autofree, dict_dir)) goto error;
 
-       if (fr_dict_internal_afrom_file(&dict_internal, FR_DICTIONARY_INTERNAL_DIR) < 0) goto error;
+       if (fr_dict_internal_afrom_file(&dict_internal, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) goto error;
 
        /*
         *      Set the root name of the dictionary
index 40cfcf7a50dae5e21d75cfa7e13959ec86533602..c37561dd09940c2e802d74e23edc3b869d7d6118 100644 (file)
@@ -826,24 +826,25 @@ static int local_command(char *line)
 
 int main(int argc, char **argv)
 {
-       int             c;
-       bool            quiet = false;
-       char            *line = NULL;
-       ssize_t         result;
-       char const      *file = NULL;
-       char const      *name = "radiusd";
-       char const      *input_file = NULL;
-       FILE            *inputfp = stdin;
-       char const      *server = NULL;
-       fr_dict_t       *dict = NULL;
-
-       char const      *raddb_dir = RADIUS_DIR;
-       char const      *dict_dir = DICTDIR;
+       int                     c;
+       bool                    quiet = false;
+       char                    *line = NULL;
+       ssize_t                 result;
+       char const              *file = NULL;
+       char const              *name = "radiusd";
+       char const              *input_file = NULL;
+       FILE                    *inputfp = stdin;
+       char const              *server = NULL;
+       fr_dict_t               *dict = NULL;
+
+       char const              *raddb_dir = RADIUS_DIR;
+       char const              *dict_dir = DICTDIR;
 #ifdef USE_READLINE_HISTORY
-       char            history_file[PATH_MAX];
+       char                    history_file[PATH_MAX];
 #endif
 
-       TALLOC_CTX      *autofree;
+       TALLOC_CTX              *autofree;
+       fr_dict_gctx_t const    *dict_gctx = NULL;
 
        char *commands[MAX_COMMANDS];
        int num_commands = -1;
@@ -975,12 +976,13 @@ int main(int argc, char **argv)
                 *      Need to read in the dictionaries, else we may get
                 *      validation errors when we try and parse the config.
                 */
-               if (!fr_dict_global_ctx_init(autofree, dict_dir)) {
+               dict_gctx = fr_dict_global_ctx_init(autofree, dict_dir);
+               if (!dict_gctx) {
                        fr_perror("radmin");
                        fr_exit_now(64);
                }
 
-               if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR) < 0) {
+               if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) {
                        fr_perror("radmin");
                        fr_exit_now(64);
                }
@@ -1319,6 +1321,10 @@ int main(int argc, char **argv)
        }
 
 exit:
+       fr_dict_free(&dict, __FILE__);
+
+       if (fr_dict_global_ctx_free(dict_gctx) < 0) fr_perror("radmin");
+
        if (inputfp != stdin) fclose(inputfp);
 
        if (radmin_log.dst == L_DST_FILES) close(radmin_log.fd);
index 8079242a1f75e8f1d7e39642c99aba1e7fea57d7..e7663db383bc64cd2be7435ebc84c7a81e1a601a 100644 (file)
@@ -138,7 +138,7 @@ int main(int argc, char **argv)
                fr_exit_now(EXIT_FAILURE);
        }
 
-       if (fr_dict_internal_afrom_file(&conf->dict, FR_DICTIONARY_FILE) < 0) {
+       if (fr_dict_internal_afrom_file(&conf->dict, FR_DICTIONARY_FILE, __FILE__) < 0) {
                fr_perror("sync_touch");
                fr_exit_now(EXIT_FAILURE);
        }