diff --git a/src/box/alter.cc b/src/box/alter.cc
index 9b29fac379c5ce16e4d08ecf55ff2b692892a396..95027043e87085469bdb22edd32eeb4abf499341 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -1687,19 +1687,37 @@ on_replace_dd_user(struct trigger * /* trigger */, void *event)
 	}
 }
 
+/**
+ * Get function identifiers from a tuple.
+ *
+ * @param tuple Tuple to get ids from.
+ * @param[out] fid Function identifier.
+ * @param[out] uid Owner identifier.
+ */
+static inline void
+func_def_get_ids_from_tuple(const struct tuple *tuple, uint32_t *fid,
+			    uint32_t *uid)
+{
+	*fid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_ID);
+	*uid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_UID);
+}
+
 /** Create a function definition from tuple. */
-static void
-func_def_create_from_tuple(struct func_def *def, struct tuple *tuple)
+static struct func_def *
+func_def_new_from_tuple(const struct tuple *tuple)
 {
-	def->fid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_ID);
-	def->uid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_UID);
-	const char *name = tuple_field_cstr_xc(tuple, BOX_FUNC_FIELD_NAME);
-	uint32_t len = strlen(name);
-	if (len >= sizeof(def->name)) {
+	uint32_t len;
+	const char *name = tuple_field_str_xc(tuple, BOX_FUNC_FIELD_NAME,
+					      &len);
+	if (len > BOX_NAME_MAX)
 		tnt_raise(ClientError, ER_CREATE_FUNCTION,
-			  name, "function name is too long");
-	}
-	snprintf(def->name, sizeof(def->name), "%s", name);
+			  tt_cstr(name, len), "function name is too long");
+	struct func_def *def = (struct func_def *) malloc(func_def_sizeof(len));
+	if (def == NULL)
+		tnt_raise(OutOfMemory, func_def_sizeof(len), "malloc", "def");
+	auto def_guard = make_scoped_guard([=] { free(def); });
+	func_def_get_ids_from_tuple(tuple, &def->fid, &def->uid);
+	snprintf(def->name, len + 1, "%s", name);
 	if (tuple_field_count(tuple) > BOX_FUNC_FIELD_SETUID)
 		def->setuid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_SETUID);
 	else
@@ -1710,12 +1728,14 @@ func_def_create_from_tuple(struct func_def *def, struct tuple *tuple)
 		def->language = STR2ENUM(func_language, language);
 		if (def->language == func_language_MAX) {
 			tnt_raise(ClientError, ER_FUNCTION_LANGUAGE,
-				  language, name);
+				  language, def->name);
 		}
 	} else {
 		/* Lua is the default. */
 		def->language = FUNC_LANGUAGE_LUA;
 	}
+	def_guard.is_active = false;
+	return def;
 }
 
 /** Remove a function from function cache */
@@ -1734,9 +1754,10 @@ static void
 func_cache_replace_func(struct trigger * /* trigger */, void *event)
 {
 	struct txn_stmt *stmt = txn_last_stmt((struct txn*) event);
-	struct func_def def;
-	func_def_create_from_tuple(&def, stmt->new_tuple);
-	func_cache_replace(&def);
+	struct func_def *def = func_def_new_from_tuple(stmt->new_tuple);
+	auto def_guard = make_scoped_guard([=] { free(def); });
+	func_cache_replace(def);
+	def_guard.is_active = false;
 }
 
 /**
@@ -1751,36 +1772,39 @@ on_replace_dd_func(struct trigger * /* trigger */, void *event)
 	struct txn_stmt *stmt = txn_current_stmt(txn);
 	struct tuple *old_tuple = stmt->old_tuple;
 	struct tuple *new_tuple = stmt->new_tuple;
-	struct func_def def;
 
 	uint32_t fid = tuple_field_u32_xc(old_tuple ? old_tuple : new_tuple,
 					  BOX_FUNC_FIELD_ID);
 	struct func *old_func = func_by_id(fid);
 	if (new_tuple != NULL && old_func == NULL) { /* INSERT */
-		func_def_create_from_tuple(&def, new_tuple);
-		func_cache_replace(&def);
+		struct func_def *def = func_def_new_from_tuple(new_tuple);
+		auto def_guard = make_scoped_guard([=] { free(def); });
+		func_cache_replace(def);
+		def_guard.is_active = false;
 		struct trigger *on_rollback =
 			txn_alter_trigger_new(func_cache_remove_func, NULL);
 		txn_on_rollback(txn, on_rollback);
 	} else if (new_tuple == NULL) {         /* DELETE */
-		func_def_create_from_tuple(&def, old_tuple);
+		uint32_t uid;
+		func_def_get_ids_from_tuple(old_tuple, &fid, &uid);
 		/*
 		 * Can only delete func if you're the one
 		 * who created it or a superuser.
 		 */
-		access_check_ddl(def.uid, SC_FUNCTION);
+		access_check_ddl(uid, SC_FUNCTION);
 		/* Can only delete func if it has no grants. */
-		if (schema_find_grants("function", old_func->def.fid)) {
+		if (schema_find_grants("function", old_func->def->fid)) {
 			tnt_raise(ClientError, ER_DROP_FUNCTION,
-				  (unsigned) old_func->def.uid,
+				  (unsigned) old_func->def->uid,
 				  "function has grants");
 		}
 		struct trigger *on_commit =
 			txn_alter_trigger_new(func_cache_remove_func, NULL);
 		txn_on_commit(txn, on_commit);
 	} else {                                /* UPDATE, REPLACE */
-		func_def_create_from_tuple(&def, new_tuple);
-		access_check_ddl(def.uid, SC_FUNCTION);
+		struct func_def *def = func_def_new_from_tuple(new_tuple);
+		auto def_guard = make_scoped_guard([=] { free(def); });
+		access_check_ddl(def->uid, SC_FUNCTION);
 		struct trigger *on_commit =
 			txn_alter_trigger_new(func_cache_replace_func, NULL);
 		txn_on_commit(txn, on_commit);
@@ -1849,7 +1873,7 @@ priv_def_check(struct priv_def *priv)
 	case SC_FUNCTION:
 	{
 		struct func *func = func_cache_find(priv->object_id);
-		if (func->def.uid != grantor->def.uid &&
+		if (func->def->uid != grantor->def.uid &&
 		    grantor->def.uid != ADMIN) {
 			tnt_raise(ClientError, ER_ACCESS_DENIED,
 				  "Grant", schema_object_name(priv->object_type),
diff --git a/src/box/box.cc b/src/box/box.cc
index 70ecf2db823227ed475288f9348914bbb288f292..a29436d4635fb399be10d89bd093186d7a818ba0 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -927,7 +927,7 @@ access_check_func(const char *name, uint32_t name_len)
 	if ((credentials->universal_access & PRIV_ALL) == PRIV_ALL)
 		return func;
 	uint8_t access = PRIV_X & ~credentials->universal_access;
-	if (func == NULL || (func->def.uid != credentials->uid &&
+	if (func == NULL || (func->def->uid != credentials->uid &&
 	     access & ~func->access[credentials->auth_token].effective)) {
 		/* Access violation, report error. */
 		char name_buf[BOX_NAME_MAX + 1];
@@ -943,7 +943,7 @@ access_check_func(const char *name, uint32_t name_len)
 int
 func_call(struct func *func, struct request *request, struct obuf *out)
 {
-	assert(func != NULL && func->def.language == FUNC_LANGUAGE_C);
+	assert(func != NULL && func->def->language == FUNC_LANGUAGE_C);
 	if (func->func == NULL)
 		func_load(func);
 
@@ -1030,7 +1030,7 @@ box_process_call(struct request *request, struct obuf *out)
 	 * defined, it's obviously not a setuid one.
 	 */
 	struct credentials *orig_credentials = NULL;
-	if (func && func->def.setuid) {
+	if (func && func->def->setuid) {
 		orig_credentials = current_user();
 		/* Remember and change the current user id. */
 		if (func->owner_credentials.auth_token >= BOX_USER_MAX) {
@@ -1040,7 +1040,7 @@ box_process_call(struct request *request, struct obuf *out)
 			 * be around to fill it (recovery of
 			 * system spaces from a snapshot).
 			 */
-			struct user *owner = user_find_xc(func->def.uid);
+			struct user *owner = user_find_xc(func->def->uid);
 			credentials_init(&func->owner_credentials,
 					 owner->auth_token,
 					 owner->def.uid);
@@ -1049,7 +1049,7 @@ box_process_call(struct request *request, struct obuf *out)
 	}
 
 	int rc;
-	if (func && func->def.language == FUNC_LANGUAGE_C) {
+	if (func && func->def->language == FUNC_LANGUAGE_C) {
 		rc = func_call(func, request, out);
 	} else {
 		rc = box_lua_call(request, out);
diff --git a/src/box/func.cc b/src/box/func.cc
index 29feba695c2dbb31aff32afac03f87600df3b22e..93390b81280e0fbc4b8f53484fafbca013777a80 100644
--- a/src/box/func.cc
+++ b/src/box/func.cc
@@ -43,7 +43,7 @@ func_new(struct func_def *def)
 		diag_set(OutOfMemory, sizeof(*func), "malloc", "func");
 		return NULL;
 	}
-	func->def = *def;
+	func->def = def;
 	/** Nobody has access to the function but the owner. */
 	memset(func->access, 0, sizeof(func->access));
 	/*
@@ -95,7 +95,7 @@ func_load(struct func *func)
 	 * E.g. name = foo.bar.baz, function = baz, package = foo.bar
 	 */
 	const char *sym;
-	const char *package = func->def.name;
+	const char *package = func->def->name;
 	const char *package_end = strrchr(package, '.');
 	if (package_end != NULL) {
 		/* module.submodule.function => module.submodule, function */
@@ -112,21 +112,21 @@ func_load(struct func *func)
 	lua_getfield(L, -3, "cpath");
 
 	if (lua_pcall(L, 2, 1, 0)) {
-		tnt_raise(ClientError, ER_LOAD_FUNCTION, func->def.name,
+		tnt_raise(ClientError, ER_LOAD_FUNCTION, func->def->name,
 			  lua_tostring(L, -1));
 	}
 	if (lua_isnil(L, -1)) {
-		tnt_raise(ClientError, ER_LOAD_FUNCTION, func->def.name,
+		tnt_raise(ClientError, ER_LOAD_FUNCTION, func->def->name,
 			  "shared library not found in the search path");
 	}
 	func->dlhandle = dlopen(lua_tostring(L, -1), RTLD_NOW | RTLD_LOCAL);
 	if (func->dlhandle == NULL) {
-		tnt_raise(LoggedError, ER_LOAD_FUNCTION, func->def.name,
+		tnt_raise(LoggedError, ER_LOAD_FUNCTION, func->def->name,
 			  dlerror());
 	}
 	func->func = (box_function_f) dlsym(func->dlhandle, sym);
 	if (func->func == NULL) {
-		tnt_raise(LoggedError, ER_LOAD_FUNCTION, func->def.name,
+		tnt_raise(LoggedError, ER_LOAD_FUNCTION, func->def->name,
 			  dlerror());
 	}
 }
@@ -135,12 +135,14 @@ void
 func_update(struct func *func, struct func_def *def)
 {
 	func_unload(func);
-	func->def = *def;
+	free(func->def);
+	func->def = def;
 }
 
 void
 func_delete(struct func *func)
 {
 	func_unload(func);
+	free(func->def);
 	free(func);
 }
diff --git a/src/box/func.h b/src/box/func.h
index f590e353ef3d083328f6c09700f33ada07839860..c29b964ea528215f4d377640e6736b8ecd569ddf 100644
--- a/src/box/func.h
+++ b/src/box/func.h
@@ -40,7 +40,7 @@ extern "C" {
  * Stored function.
  */
 struct func {
-	struct func_def def;
+	struct func_def *def;
 	/**
 	 * For C functions, the body of the function.
 	 */
diff --git a/src/box/key_def.h b/src/box/key_def.h
index 54815d2d7491c994c71c11c13905fd841f342955..39707b0bbe6c16c59c739b89ad9b2aebdfd2a71a 100644
--- a/src/box/key_def.h
+++ b/src/box/key_def.h
@@ -421,9 +421,21 @@ struct func_def {
 	 */
 	enum func_language language;
 	/** Function name. */
-	char name[BOX_NAME_MAX + 1];
+	char name[0];
 };
 
+/**
+ * @param name_length length of func_def->name
+ * @returns size in bytes needed to allocate for struct func_def
+ * for a function of length @a a name_length.
+ */
+static inline size_t
+func_def_sizeof(uint32_t name_length)
+{
+	/* +1 for '\0' name terminating. */
+	return sizeof(struct func_def) + name_length + 1;
+}
+
 /**
  * Definition of a privilege
  */
diff --git a/src/box/schema.cc b/src/box/schema.cc
index 7feb18653d10986d02a788f66f27e6024ada74a6..555fb36f6e14394dbf461280203fe5f79b737c03 100644
--- a/src/box/schema.cc
+++ b/src/box/schema.cc
@@ -353,7 +353,7 @@ schema_free(void)
 
 		struct func *func = ((struct func *)
 				     mh_i32ptr_node(funcs, i)->val);
-		func_cache_delete(func->def.fid);
+		func_cache_delete(func->def->fid);
 	}
 	mh_i32ptr_delete(funcs);
 }
@@ -377,17 +377,19 @@ func_cache_replace(struct func_def *def)
 	const struct mh_i32ptr_node_t node = { def->fid, func };
 	mh_int_t k1 = mh_i32ptr_put(funcs, &node, NULL, NULL);
 	if (k1 == mh_end(funcs)) {
+		func->def = NULL;
 		func_delete(func);
 		goto error;
 	}
-	size_t def_name_len = strlen(func->def.name);
-	uint32_t name_hash = mh_strn_hash(func->def.name, def_name_len);
+	size_t def_name_len = strlen(func->def->name);
+	uint32_t name_hash = mh_strn_hash(func->def->name, def_name_len);
 	const struct mh_strnptr_node_t strnode = {
-		func->def.name, def_name_len, name_hash, func };
+		func->def->name, def_name_len, name_hash, func };
 
 	mh_int_t k2 = mh_strnptr_put(funcs_by_name, &strnode, NULL, NULL);
 	if (k2 == mh_end(funcs_by_name)) {
 		mh_i32ptr_del(funcs, k1, NULL);
+		func->def = NULL;
 		func_delete(func);
 		goto error;
 	}
@@ -402,8 +404,8 @@ func_cache_delete(uint32_t fid)
 	struct func *func = (struct func *)
 		mh_i32ptr_node(funcs, k)->val;
 	mh_i32ptr_del(funcs, k, NULL);
-	k = mh_strnptr_find_inp(funcs_by_name, func->def.name,
-				strlen(func->def.name));
+	k = mh_strnptr_find_inp(funcs_by_name, func->def->name,
+				strlen(func->def->name));
 	if (k != mh_end(funcs))
 		mh_strnptr_del(funcs_by_name, k, NULL);
 	func_delete(func);
diff --git a/src/box/schema.h b/src/box/schema.h
index 61bced142e9c80151b92990ff948ebd97e1ec0d4..7832f132c7fa5e03193c64f8f227105e4ec38354 100644
--- a/src/box/schema.h
+++ b/src/box/schema.h
@@ -214,6 +214,13 @@ uint32_t
 schema_find_id(uint32_t system_space_id, uint32_t index_id,
 	       const char *name, uint32_t len);
 
+/**
+ * Insert a new function or update the old one.
+ *
+ * @param def Function definition. In a case of success the ownership
+ *        of @a def is transfered to the data dictionary, thus the caller
+ *        must not delete it.
+ */
 void
 func_cache_replace(struct func_def *def);
 
diff --git a/src/box/sysview_index.cc b/src/box/sysview_index.cc
index 1b3ad170ed03c8fc86f5d63378d7f0e9e9b28418..33f5f9f1df693019c4f7811954059735a0c723d9 100644
--- a/src/box/sysview_index.cc
+++ b/src/box/sysview_index.cc
@@ -221,7 +221,7 @@ vfunc_filter(struct space *source, struct tuple *tuple)
 	struct func *func = func_by_name(name, name_len);
 	assert(func != NULL);
 	uint8_t effective = func->access[cr->auth_token].effective;
-	if (func->def.uid == cr->uid || (PRIV_X & effective))
+	if (func->def->uid == cr->uid || (PRIV_X & effective))
 		return true;
 	return false;
 }
diff --git a/src/box/tuple.h b/src/box/tuple.h
index 2a8fdc34621304fbd0424298f945cc31bfdfe39d..e842d5885d10f0b1ab9c1b7c7237d9609e9352f8 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -604,16 +604,28 @@ tuple_field_u32(const struct tuple *tuple, uint32_t fieldno, uint32_t *out)
 
 /**
  * A convenience shortcut for data dictionary - get a tuple field
- * as a NUL-terminated string - returns a string of up to 256 bytes.
+ * as a string.
  */
 static inline const char *
-tuple_field_cstr(const struct tuple *tuple, uint32_t fieldno)
+tuple_field_str(const struct tuple *tuple, uint32_t fieldno, uint32_t *len)
 {
 	const char *field = tuple_field_with_type(tuple, fieldno, MP_STR);
 	if (field == NULL)
 		return NULL;
-	uint32_t len = 0;
-	const char *str = mp_decode_str(&field, &len);
+	return mp_decode_str(&field, len);
+}
+
+/**
+ * A convenience shortcut for data dictionary - get a tuple field
+ * as a NUL-terminated string - returns a string of up to 256 bytes.
+ */
+static inline const char *
+tuple_field_cstr(const struct tuple *tuple, uint32_t fieldno)
+{
+	uint32_t len;
+	const char *str = tuple_field_str(tuple, fieldno, &len);
+	if (str == NULL)
+		return NULL;
 	return tt_cstr(str, len);
 }
 
@@ -771,6 +783,17 @@ tuple_field_u32_xc(const struct tuple *tuple, uint32_t fieldno)
 	return out;
 }
 
+/** @copydoc tuple_field_str() */
+static inline const char *
+tuple_field_str_xc(const struct tuple *tuple, uint32_t fieldno,
+			uint32_t *len)
+{
+	const char *ret = tuple_field_str(tuple, fieldno, len);
+	if (ret == NULL)
+		diag_raise();
+	return ret;
+}
+
 /** @copydoc tuple_field_cstr() */
 static inline const char *
 tuple_field_cstr_xc(const struct tuple *tuple, uint32_t fieldno)