From 635675e89c2fd6ae2a6e9924eb20be086978d91d Mon Sep 17 00:00:00 2001
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
Date: Thu, 24 Aug 2017 20:35:12 +0300
Subject: [PATCH] sql: fix memleak in index_opts

---
 src/box/alter.cc    |  2 ++
 src/box/index_def.c | 44 +++++++++++++++++++-------------------------
 src/box/index_def.h |  6 ++++++
 3 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index c713226de7..1d65cc9c22 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -311,6 +311,8 @@ index_def_new_from_tuple(struct tuple *tuple, struct space *old_space)
 			  space_name(old_space), "index name is too long");
 	}
 	index_opts_create(&opts, tuple_field(tuple, BOX_INDEX_FIELD_OPTS));
+	struct index_opts *opts_p = &opts;
+	auto opts_guard = make_scoped_guard([=] { index_opts_destroy(opts_p); });
 	const char *parts = tuple_field(tuple, BOX_INDEX_FIELD_PARTS);
 	uint32_t part_count = mp_decode_array(&parts);
 	struct key_def *key_def = key_def_new(part_count);
diff --git a/src/box/index_def.c b/src/box/index_def.c
index 14956cb00f..806ac121b4 100644
--- a/src/box/index_def.c
+++ b/src/box/index_def.c
@@ -63,30 +63,6 @@ const struct opt_def index_opts_reg[] = {
 	{ NULL, opt_type_MAX, 0, 0 },
 };
 
-/**
- * Destructor for struct index_opts.
- * The only relevant action so far is to free sql field if not-null.
- */
-static void
-index_opts_destroy(struct index_opts *opts)
-{
-	if (opts->sql) {
-		free(opts->sql);
-		opts->sql = 0;
-	}
-}
-
-static void
-index_opts_dup(struct index_opts *dst, const struct index_opts *src)
-{
-	*dst = *src;
-	if (src->sql) {
-		dst->sql = (char*)strdup(src->sql);
-		if (dst->sql == NULL)
-			diag_set(OutOfMemory, strlen(src->sql), "sql", "char *");
-	}
-}
-
 struct index_def *
 index_def_new(uint32_t space_id, uint32_t iid, const char *name,
 	      uint32_t name_len, enum index_type type,
@@ -124,6 +100,15 @@ index_def_new(uint32_t space_id, uint32_t iid, const char *name,
 	def->space_id = space_id;
 	def->iid = iid;
 	def->opts = *opts;
+	if (opts->sql != NULL) {
+		def->opts.sql = strdup(opts->sql);
+		if (def->opts.sql == NULL) {
+			diag_set(OutOfMemory, strlen(opts->sql) + 1, "strdup",
+				 "def->opts.sql");
+			index_def_delete(def);
+			return NULL;
+		}
+	}
 	return def;
 }
 
@@ -151,7 +136,16 @@ index_def_dup(const struct index_def *def)
 		return NULL;
 	}
 	rlist_create(&dup->link);
-	index_opts_dup(&dup->opts, &def->opts);
+	dup->opts = def->opts;
+	if (def->opts.sql != NULL) {
+		dup->opts.sql = strdup(def->opts.sql);
+		if (dup->opts.sql == NULL) {
+			diag_set(OutOfMemory, strlen(def->opts.sql) + 1,
+				 "strdup", "dup->opts.sql");
+			index_def_delete(dup);
+			return NULL;
+		}
+	}
 	return dup;
 }
 
diff --git a/src/box/index_def.h b/src/box/index_def.h
index ed466aed2f..2ce4d702f9 100644
--- a/src/box/index_def.h
+++ b/src/box/index_def.h
@@ -102,6 +102,12 @@ struct index_opts {
 	char *sql;
 };
 
+static inline void
+index_opts_destroy(struct index_opts *opts)
+{
+	free(opts->sql);
+}
+
 extern const struct index_opts index_opts_default;
 extern const struct opt_def index_opts_reg[];
 
-- 
GitLab