diff --git a/changelogs/unreleased/gh-5310-fix-cursor-invalidation.md b/changelogs/unreleased/gh-5310-fix-cursor-invalidation.md new file mode 100644 index 0000000000000000000000000000000000000000..e4878e2b31f873798e200c65a281a695f260cfaa --- /dev/null +++ b/changelogs/unreleased/gh-5310-fix-cursor-invalidation.md @@ -0,0 +1,4 @@ +## bugfix/sql + +* Fixed a crash that could occur when tuples longer than specified in + the format were selected (gh-5310). diff --git a/src/box/sql.c b/src/box/sql.c index a02376740f74c2888a17960a42829ca27d4c1ba6..da9ecea80a4dd3b52c0f812068061e0fa46d792a 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -1377,8 +1377,15 @@ vdbe_field_ref_create(struct vdbe_field_ref *field_ref, struct tuple *tuple, field_ref->data_sz = data_sz; const char *field0 = data; - field_ref->field_count = mp_decode_array((const char **) &field0); field_ref->format = NULL; + uint32_t mp_count = mp_decode_array(&field0); + if (tuple != NULL) { + assert(tuple_format(tuple) != NULL); + uint32_t field_count = tuple_format(tuple)->total_field_count; + field_ref->field_count = MIN(field_count, mp_count); + } else { + field_ref->field_count = mp_count; + } field_ref->slots[0] = (uint32_t)(field0 - data); memset(&field_ref->slots[1], 0, field_ref->field_count * sizeof(field_ref->slots[0])); diff --git a/test/sql-luatest/gh_5310_cursor_invalidation_test.lua b/test/sql-luatest/gh_5310_cursor_invalidation_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..508249ad9469e56dbb7d028266e67369136d6de4 --- /dev/null +++ b/test/sql-luatest/gh_5310_cursor_invalidation_test.lua @@ -0,0 +1,24 @@ +local server = require('test.luatest_helpers.server') +local t = require('luatest') +local g = t.group() + +g.before_all(function() + g.server = server:new({alias = 'test_cursor_invalidation'}) + g.server:start() +end) + +g.after_all(function() + g.server:stop() +end) + +g.test_cursor_invalidation = function() + g.server:exec(function() + local t = require('luatest') + local s = box.schema.space.create('T', {format = {'A'}}) + s:create_index('ii') + s:insert({1,2,3,4,5}) + s:insert({2}) + t.assert_equals(box.execute([[SELECT * FROM t;]]).rows, {{1}, {2}}) + s:drop() + end) +end