]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Fixed memory leak when parsing settings.
authorTimo Sirainen <tss@iki.fi>
Mon, 5 Apr 2010 20:06:19 +0000 (23:06 +0300)
committerTimo Sirainen <tss@iki.fi>
Mon, 5 Apr 2010 20:06:19 +0000 (23:06 +0300)
--HG--
branch : HEAD

src/lib-master/master-service-settings-cache.c
src/lib-master/master-service-settings-cache.h
src/lib-master/master-service-settings.h
src/lib-settings/settings-parser.c
src/lib-settings/settings-parser.h
src/lib-storage/mail-storage-service.c
src/login-common/login-settings.c

index 97570d9339f9137a5c18f38175f31461f333b604..4c240586d7747a73115e4f5238ef84444142ad20 100644 (file)
@@ -253,10 +253,12 @@ static void cache_add(struct master_service_settings_cache *cache,
 
 int master_service_settings_cache_read(struct master_service_settings_cache *cache,
                                       const struct master_service_settings_input *input,
+                                      const struct dynamic_settings_parser *dyn_parsers,
                                       const struct setting_parser_context **parser_r,
                                       const char **error_r)
 {
        struct master_service_settings_output output;
+       struct master_service_settings_input new_input;
        const struct master_service_settings *set;
 
        i_assert(null_strcmp(input->module, cache->module) == 0);
@@ -265,7 +267,12 @@ int master_service_settings_cache_read(struct master_service_settings_cache *cac
        if (cache_find(cache, input, parser_r))
                return 0;
 
-       if (master_service_settings_read(cache->service, input,
+       new_input = *input;
+       if (dyn_parsers != NULL) {
+               settings_parser_dyn_update(cache->pool, &new_input.roots,
+                                          dyn_parsers);
+       }
+       if (master_service_settings_read(cache->service, &new_input,
                                         &output, error_r) < 0)
                return -1;
 
@@ -287,7 +294,7 @@ int master_service_settings_cache_read(struct master_service_settings_cache *cac
                return -1;
        }
 
-       cache_add(cache, input, &output, cache->service->set_parser);
+       cache_add(cache, &new_input, &output, cache->service->set_parser);
        *parser_r = cache->service->set_parser;
        return 0;
 }
index 200dad495831a81ca3644c92dd8988d2d59c4e76..84754fb6fb79e72513d2d9dde312c2f558304de4 100644 (file)
@@ -9,6 +9,7 @@ void master_service_settings_cache_deinit(struct master_service_settings_cache *
 
 int master_service_settings_cache_read(struct master_service_settings_cache *cache,
                                       const struct master_service_settings_input *input,
+                                      const struct dynamic_settings_parser *dyn_parsers,
                                       const struct setting_parser_context **parser_r,
                                       const char **error_r);
 
index 0ddde37f85b3d35616eb3b22597bbca3ce5bba99..0624c87d67e45bf67d56a86b7bd63eb6e27092bb 100644 (file)
@@ -18,7 +18,7 @@ struct master_service_settings {
 };
 
 struct master_service_settings_input {
-       const struct setting_parser_info **roots;
+       const struct setting_parser_info *const *roots;
        const char *config_path;
        bool preserve_home;
        bool never_exec;
index 889e63961f8017845a173cbc89979d6a7e4a16e9..876f2d7a5e557c393f7bec0e5fb9716a9856b2a0 100644 (file)
@@ -259,6 +259,18 @@ void *settings_parser_get_changes(struct setting_parser_context *ctx)
        return ctx->roots[0].change_struct;
 }
 
+const struct setting_parser_info *const *
+settings_parser_get_roots(const struct setting_parser_context *ctx)
+{
+       const struct setting_parser_info **infos;
+       unsigned int i;
+
+       infos = t_new(const struct setting_parser_info *, ctx->root_count + 1);
+       for (i = 0; i < ctx->root_count; i++)
+               infos[i] = ctx->roots[i].info;
+       return infos;
+}
+
 const char *settings_parser_get_error(struct setting_parser_context *ctx)
 {
        return ctx->error;
@@ -1473,6 +1485,76 @@ void settings_parser_info_update(pool_t pool,
        } T_END;
 }
 
+static void
+settings_parser_update_children_parent(struct setting_parser_info *parent,
+                                      pool_t pool)
+{
+       struct setting_define *new_defs;
+       struct setting_parser_info *new_info;
+       unsigned int i, count;
+
+       for (count = 0; parent->defines[count].key != NULL; count++) ;
+
+       new_defs = p_new(pool, struct setting_define, count + 1);
+       memcpy(new_defs, parent->defines, sizeof(*new_defs) * count);
+       parent->defines = new_defs;
+
+       for (i = 0; i < count; i++) {
+               if (new_defs[i].list_info == NULL ||
+                   new_defs[i].list_info->parent == NULL)
+                       continue;
+
+               new_info = p_new(pool, struct setting_parser_info, 1);
+               *new_info = *new_defs[i].list_info;
+               new_info->parent = parent;
+               new_defs[i].list_info = new_info;
+       }
+}
+
+void settings_parser_dyn_update(pool_t pool,
+                               const struct setting_parser_info *const **_roots,
+                               const struct dynamic_settings_parser *dyn_parsers)
+{
+       const struct setting_parser_info *const *roots = *_roots;
+       const struct setting_parser_info *old_parent, **new_roots;
+       struct setting_parser_info *new_parent, *new_info;
+       struct dynamic_settings_parser *new_dyn_parsers;
+       unsigned int i, count;
+
+       /* settings_parser_info_update() modifies the parent structure.
+          since we may be using the same structure later, we want it to be
+          in its original state, so we'll have to copy all structures. */
+       old_parent = dyn_parsers[0].info->parent;
+       new_parent = p_new(pool, struct setting_parser_info, 1);
+       *new_parent = *old_parent;
+       settings_parser_update_children_parent(new_parent, pool);
+
+       /* update root */
+       for (count = 0; roots[count] != NULL; count++) ;
+       new_roots = p_new(pool, const struct setting_parser_info *, count + 1);
+       for (i = 0; i < count; i++) {
+               if (roots[i] == old_parent)
+                       new_roots[i] = new_parent;
+               else
+                       new_roots[i] = roots[i];
+       }
+       *_roots = new_roots;
+
+       /* update parent in dyn_parsers */
+       for (count = 0; dyn_parsers[count].name != NULL; count++) ;
+       new_dyn_parsers = p_new(pool, struct dynamic_settings_parser, count + 1);
+       for (i = 0; i < count; i++) {
+               new_dyn_parsers[i] = dyn_parsers[i];
+
+               new_info = p_new(pool, struct setting_parser_info, 1);
+               *new_info = *dyn_parsers[i].info;
+               new_info->parent = new_parent;
+               new_dyn_parsers[i].info = new_info;
+       }
+
+       settings_parser_info_update(pool, new_parent, new_dyn_parsers);
+}
+
 const void *settings_find_dynamic(const struct setting_parser_info *info,
                                  const void *base_set, const char *name)
 {
index 583632d201c5dcd63a790e5eb63f9ff6f3699860..76a1997f164e3dcfae0e378745e77712422dcc78 100644 (file)
@@ -114,6 +114,9 @@ void *settings_parser_get(struct setting_parser_context *ctx);
 void **settings_parser_get_list(const struct setting_parser_context *ctx);
 /* Like settings_parser_get(), but return change struct. */
 void *settings_parser_get_changes(struct setting_parser_context *ctx);
+/* Returns the setting parser's roots (same as given to init()). */
+const struct setting_parser_info *const *
+settings_parser_get_roots(const struct setting_parser_context *ctx);
 
 /* Return the last error. */
 const char *settings_parser_get_error(struct setting_parser_context *ctx);
@@ -194,6 +197,9 @@ settings_parser_dup(const struct setting_parser_context *old_ctx,
 void settings_parser_info_update(pool_t pool,
                                 struct setting_parser_info *parent,
                                 const struct dynamic_settings_parser *parsers);
+void settings_parser_dyn_update(pool_t pool,
+                               const struct setting_parser_info *const **roots,
+                               const struct dynamic_settings_parser *dyn_parsers);
 
 /* Return pointer to beginning of settings for given name, or NULL if there is
    no such registered name. */
index 721daa449c56e470913dbfcf732508bbfdd993b9..efff7ad0c40f4eef8181f747f6c0ef8355bdaec6 100644 (file)
@@ -49,7 +49,6 @@ struct mail_storage_service_ctx {
 
        const char *set_cache_module, *set_cache_service;
        struct master_service_settings_cache *set_cache;
-       const struct setting_parser_info **set_cache_roots;
 
        unsigned int debug:1;
 };
@@ -591,77 +590,6 @@ mail_storage_service_get_auth_conn(struct mail_storage_service_ctx *ctx)
        return ctx->conn;
 }
 
-static void
-settings_parser_update_children_parent(struct setting_parser_info *parent,
-                                      pool_t pool)
-{
-       struct setting_define *new_defs;
-       struct setting_parser_info *new_info;
-       unsigned int i, count;
-
-       for (count = 0; parent->defines[count].key != NULL; count++) ;
-
-       new_defs = p_new(pool, struct setting_define, count + 1);
-       memcpy(new_defs, parent->defines, sizeof(*new_defs) * count);
-       parent->defines = new_defs;
-
-       for (i = 0; i < count; i++) {
-               if (new_defs[i].list_info == NULL ||
-                   new_defs[i].list_info->parent == NULL)
-                       continue;
-
-               new_info = p_new(pool, struct setting_parser_info, 1);
-               *new_info = *new_defs[i].list_info;
-               new_info->parent = parent;
-               new_defs[i].list_info = new_info;
-       }
-}
-
-static void
-dyn_parsers_update_parent(pool_t pool,
-                         const struct setting_parser_info ***_roots,
-                         const struct dynamic_settings_parser *dyn_parsers)
-{
-       const const struct setting_parser_info **roots = *_roots;
-       const struct setting_parser_info *old_parent, **new_roots;
-       struct setting_parser_info *new_parent, *new_info;
-       struct dynamic_settings_parser *new_dyn_parsers;
-       unsigned int i, count;
-
-       /* settings_parser_info_update() modifies the parent structure.
-          since we may be using the same structure later, we want it to be
-          in its original state, so we'll have to copy all structures. */
-       old_parent = dyn_parsers[0].info->parent;
-       new_parent = p_new(pool, struct setting_parser_info, 1);
-       *new_parent = *old_parent;
-       settings_parser_update_children_parent(new_parent, pool);
-
-       /* update root */
-       for (count = 0; roots[count] != NULL; count++) ;
-       new_roots = p_new(pool, const struct setting_parser_info *, count + 1);
-       for (i = 0; i < count; i++) {
-               if (roots[i] == old_parent)
-                       new_roots[i] = new_parent;
-               else
-                       new_roots[i] = roots[i];
-       }
-       *_roots = new_roots;
-
-       /* update parent in dyn_parsers */
-       for (count = 0; dyn_parsers[count].name != NULL; count++) ;
-       new_dyn_parsers = p_new(pool, struct dynamic_settings_parser, count + 1);
-       for (i = 0; i < count; i++) {
-               new_dyn_parsers[i] = dyn_parsers[i];
-
-               new_info = p_new(pool, struct setting_parser_info, 1);
-               *new_info = *dyn_parsers[i].info;
-               new_info->parent = new_parent;
-               new_dyn_parsers[i].info = new_info;
-       }
-
-       settings_parser_info_update(pool, new_parent, new_dyn_parsers);
-}
-
 int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
                                       const struct mail_storage_service_input *input,
                                       pool_t pool,
@@ -670,6 +598,7 @@ int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
                                       const char **error_r)
 {
        struct master_service_settings_input set_input;
+       const struct setting_parser_info *const *roots;
        struct master_service_settings_output set_output;
        const struct dynamic_settings_parser *dyn_parsers;
        unsigned int i;
@@ -694,7 +623,6 @@ int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
                ctx->set_cache_service = p_strdup(ctx->pool, set_input.service);
                ctx->set_cache = master_service_settings_cache_init(
                        ctx->service, set_input.module, set_input.service);
-               ctx->set_cache_roots = ctx->set_roots;
        } else {
                /* already looked up settings at least once.
                   we really shouldn't be execing anymore. */
@@ -704,18 +632,15 @@ int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
        dyn_parsers = mail_storage_get_dynamic_parsers(pool);
        if (null_strcmp(set_input.module, ctx->set_cache_module) == 0 &&
            null_strcmp(set_input.service, ctx->set_cache_service) == 0) {
-               set_input.roots = ctx->set_cache_roots;
-               dyn_parsers_update_parent(ctx->pool, &set_input.roots,
-                                         dyn_parsers);
                if (master_service_settings_cache_read(ctx->set_cache,
-                                                      &set_input,
+                                                      &set_input, dyn_parsers,
                                                       parser_r, error_r) < 0) {
                        *error_r = t_strdup_printf(
                                "Error reading configuration: %s", *error_r);
                        return -1;
                }
        } else {
-               dyn_parsers_update_parent(pool, &set_input.roots, dyn_parsers);
+               settings_parser_dyn_update(pool, &set_input.roots, dyn_parsers);
                if (master_service_settings_read(ctx->service, &set_input,
                                                 &set_output, error_r) < 0) {
                        *error_r = t_strdup_printf(
@@ -725,10 +650,11 @@ int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
                *parser_r = ctx->service->set_parser;
        }
 
-       for (i = 0; ctx->set_roots[i] != NULL; i++) {
-               if (strcmp(ctx->set_roots[i]->module_name,
+       roots = settings_parser_get_roots(*parser_r);
+       for (i = 0; roots[i] != NULL; i++) {
+               if (strcmp(roots[i]->module_name,
                           mail_user_setting_parser_info.module_name) == 0) {
-                       *user_info_r = set_input.roots[i];
+                       *user_info_r = roots[i];
                        return 0;
                }
        }
index d9828e71c7c72a5d1e37804a9f566dd0f15f095e..163189e59818fd0aec567e6e288479df10eda73d 100644 (file)
@@ -207,7 +207,7 @@ login_settings_read(pool_t pool,
                                                               input.service);
        }
 
-       if (master_service_settings_cache_read(set_cache, &input,
+       if (master_service_settings_cache_read(set_cache, &input, NULL,
                                               &parser, &error) < 0)
                i_fatal("Error reading configuration: %s", error);