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

Nikita Pettik korablev at tarantool.org
Wed Sep 18 18:16:12 MSK 2019


On 18 Sep 15:48, Kirill Shcherbatov wrote:
> 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
> ---

We've discussed verbally real origins of this issue. I've also found
crashing query due to the same reason: inside OP_RowData region is
used to carry blob values without explicit tracking of its lifetime.
As a result, if box.space:select() is called between OP_RowData and
next access to the allocated on region blob, the last results in crash.
Investigating usages during query compilation, I come up with following
example:

WITH RECURSIVE w AS ( SELECT s1 FROM ts UNION ALL SELECT s1+1  FROM w WHERE s1 < 4) SELECT _c(s1) FROM w;

Substituting region with malloc fixes this problem.

> 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