dovecot-2.0: Fixed memory leak when parsing settings.

dovecot at dovecot.org dovecot at dovecot.org
Mon Apr 5 23:06:23 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/46d4f3264417
changeset: 11078:46d4f3264417
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Apr 05 23:06:19 2010 +0300
description:
Fixed memory leak when parsing settings.

diffstat:

 src/lib-master/master-service-settings-cache.c |  11 +++-
 src/lib-master/master-service-settings-cache.h |   1 +
 src/lib-master/master-service-settings.h       |   2 +-
 src/lib-settings/settings-parser.c             |  82 +++++++++++++++++++++++++++
 src/lib-settings/settings-parser.h             |   6 ++
 src/lib-storage/mail-storage-service.c         |  88 ++---------------------------
 src/login-common/login-settings.c              |   2 +-
 7 files changed, 107 insertions(+), 85 deletions(-)

diffs (truncated from 337 to 300 lines):

diff -r 8627be1f6de9 -r 46d4f3264417 src/lib-master/master-service-settings-cache.c
--- a/src/lib-master/master-service-settings-cache.c	Mon Apr 05 11:04:20 2010 +0300
+++ b/src/lib-master/master-service-settings-cache.c	Mon Apr 05 23:06:19 2010 +0300
@@ -253,10 +253,12 @@
 
 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 @@
 	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 @@
 		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;
 }
diff -r 8627be1f6de9 -r 46d4f3264417 src/lib-master/master-service-settings-cache.h
--- a/src/lib-master/master-service-settings-cache.h	Mon Apr 05 11:04:20 2010 +0300
+++ b/src/lib-master/master-service-settings-cache.h	Mon Apr 05 23:06:19 2010 +0300
@@ -9,6 +9,7 @@
 
 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);
 
diff -r 8627be1f6de9 -r 46d4f3264417 src/lib-master/master-service-settings.h
--- a/src/lib-master/master-service-settings.h	Mon Apr 05 11:04:20 2010 +0300
+++ b/src/lib-master/master-service-settings.h	Mon Apr 05 23:06:19 2010 +0300
@@ -18,7 +18,7 @@
 };
 
 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;
diff -r 8627be1f6de9 -r 46d4f3264417 src/lib-settings/settings-parser.c
--- a/src/lib-settings/settings-parser.c	Mon Apr 05 11:04:20 2010 +0300
+++ b/src/lib-settings/settings-parser.c	Mon Apr 05 23:06:19 2010 +0300
@@ -259,6 +259,18 @@
 	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 @@
 	} 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)
 {
diff -r 8627be1f6de9 -r 46d4f3264417 src/lib-settings/settings-parser.h
--- a/src/lib-settings/settings-parser.h	Mon Apr 05 11:04:20 2010 +0300
+++ b/src/lib-settings/settings-parser.h	Mon Apr 05 23:06:19 2010 +0300
@@ -114,6 +114,9 @@
 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 @@
 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. */
diff -r 8627be1f6de9 -r 46d4f3264417 src/lib-storage/mail-storage-service.c
--- a/src/lib-storage/mail-storage-service.c	Mon Apr 05 11:04:20 2010 +0300
+++ b/src/lib-storage/mail-storage-service.c	Mon Apr 05 23:06:19 2010 +0300
@@ -49,7 +49,6 @@
 
 	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 @@
 	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 @@
 				       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 @@
 		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 @@
 	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) {


More information about the dovecot-cvs mailing list