[tarantool-patches] [PATCH v1 1/1] sql: fix double mem release on Lua function

Kirill Shcherbatov kshcherbatov at tarantool.org
Wed Sep 18 15:48:37 MSK 2019


An region's integrity assertion used to be triggered with
recursive SQL request calling Lua function. This happened because
of invalid usage of region_truncate routine: the preparatory
region_used call used to be called in a wrong place, before
function call itself that may allocate and release memory on
region by it's own.

Closes #4504
---
Branch: http://github.com/tarantool/tarantool/tree/kshch/gh-4504-func-recursion-region
Issue: https://github.com/tarantool/tarantool/issues/4504

 src/box/sql/vdbe.c          |  4 ++--
 test/box/function1.result   | 35 +++++++++++++++++++++++++++++++++++
 test/box/function1.test.lua | 20 ++++++++++++++++++++
 3 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 8c4acdee2..9580d944e 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -1842,14 +1842,14 @@ case OP_Function: {
 	struct Mem *argv = &aMem[pOp->p2];
 	struct port args, ret;
 
-	struct region *region = &fiber()->gc;
-	size_t region_svp = region_used(region);
 	port_vdbemem_create(&args, (struct sql_value *)argv, argc);
 	if (func_call(func, &args, &ret) != 0)
 		goto abort_due_to_error;
 
 	pOut = vdbe_prepare_null_out(p, pOp->p3);
 	uint32_t size;
+	struct region *region = &fiber()->gc;
+	size_t region_svp = region_used(region);
 	struct Mem *mem = (struct Mem *)port_get_vdbemem(&ret, &size);
 	if (mem != NULL && size > 0)
 		*pOut = mem[0];
diff --git a/test/box/function1.result b/test/box/function1.result
index a41ca4e3c..0838f2774 100644
--- a/test/box/function1.result
+++ b/test/box/function1.result
@@ -1032,3 +1032,38 @@ box.func['test'].is_multikey == true
 box.func['test']:drop()
 ---
 ...
+--
+-- gh-4504: Region integrity assertion with recursive sql request
+--          involving Lua function.
+--
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+box.schema.func.create('_C', {
+	language = 'LUA', returns = 'string',
+	body = [[function (i)
+			print(i)
+			local m = box.space._space:select()
+			return 0
+		end
+		]],
+	param_list = {'integer'}, exports = {'LUA', 'SQL'},
+	is_sandboxed = false, is_deterministic = true})
+test_run:cmd("setopt delimiter ''");
+---
+...
+box.execute([[WITH RECURSIVE x AS (SELECT 0 AS q, 1 UNION ALL SELECT q+1, _c(q) FROM x WHERE q < 1) SELECT * FROM x;]])
+---
+- metadata:
+  - name: Q
+    type: integer
+  - name: '1'
+    type: integer
+  rows:
+  - [0, 1]
+  - [1, 0]
+...
+box.func._C:drop()
+---
+...
diff --git a/test/box/function1.test.lua b/test/box/function1.test.lua
index e576cbb6f..b0b77fc06 100644
--- a/test/box/function1.test.lua
+++ b/test/box/function1.test.lua
@@ -368,3 +368,23 @@ box.schema.func.drop("SUM")
 box.schema.func.create('test', {body = "function(tuple) return tuple end", is_deterministic = true, opts = {is_multikey = true}})
 box.func['test'].is_multikey == true
 box.func['test']:drop()
+
+--
+-- gh-4504: Region integrity assertion with recursive sql request
+--          involving Lua function.
+--
+test_run:cmd("setopt delimiter ';'")
+box.schema.func.create('_C', {
+	language = 'LUA', returns = 'string',
+	body = [[function (i)
+			print(i)
+			local m = box.space._space:select()
+			return 0
+		end
+		]],
+	param_list = {'integer'}, exports = {'LUA', 'SQL'},
+	is_sandboxed = false, is_deterministic = true})
+test_run:cmd("setopt delimiter ''");
+
+box.execute([[WITH RECURSIVE x AS (SELECT 0 AS q, 1 UNION ALL SELECT q+1, _c(q) FROM x WHERE q < 1) SELECT * FROM x;]])
+box.func._C:drop()
-- 
2.23.0





More information about the Tarantool-patches mailing list