diff --git a/changelogs/unreleased/gh-8899-compare-with-key-slowpath-invalid-memory-access.md b/changelogs/unreleased/gh-8899-compare-with-key-slowpath-invalid-memory-access.md new file mode 100644 index 0000000000000000000000000000000000000000..24a4d4a5569a7b7f2bb17b83a90c1eaadaf46da3 --- /dev/null +++ b/changelogs/unreleased/gh-8899-compare-with-key-slowpath-invalid-memory-access.md @@ -0,0 +1,4 @@ +## bugfix/box + +* Fixed the invalid memory access in a corner case of a specialized comparison + function (gh-8899). diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc index 83d0cc0b1191aa4eca6d26dc1e7b29ebeb74db88..b7277518476dcc1841363e875509359c5e1d16d7 100644 --- a/src/box/tuple_compare.cc +++ b/src/box/tuple_compare.cc @@ -941,8 +941,9 @@ tuple_compare_with_key_sequential(struct tuple *tuple, hint_t tuple_hint, cmp_part_count = part_count; } bool unused; - rc = key_compare_parts<is_nullable>(tuple_key, key, cmp_part_count, - key_def, &unused); + rc = key_compare_and_skip_parts<is_nullable>(&tuple_key, &key, + cmp_part_count, + key_def, &unused); if (!has_optional_parts || rc != 0) return rc; /* @@ -950,11 +951,6 @@ tuple_compare_with_key_sequential(struct tuple *tuple, hint_t tuple_hint, * corresponding key fields to be equal to NULL. */ if (field_count < part_count) { - /* - * Key's and tuple's first field_count fields are - * equal, and their bsize too. - */ - key += tuple_bsize(tuple) - mp_sizeof_array(field_count); for (uint32_t i = field_count; i < part_count; ++i, mp_next(&key)) { if (mp_typeof(*key) != MP_NIL) diff --git a/test/box-luatest/gh_8899_tuple_compare_with_key_slowpath_last_loop_test.lua b/test/box-luatest/gh_8899_tuple_compare_with_key_slowpath_last_loop_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..0d302491a12a409b0a09b13215f346b00b0be1a7 --- /dev/null +++ b/test/box-luatest/gh_8899_tuple_compare_with_key_slowpath_last_loop_test.lua @@ -0,0 +1,41 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group('gh-8899-tuple-compare-with-key-slowpath-last-loop') + +g.before_all(function() + g.server = server:new() + g.server:start() +end) + +g.after_all(function() + g.server:stop() +end) + +g.test_tuple_compare_with_key_slowpath_last_loop = function() + g.server:exec(function() + local ffi = require('ffi') + + local function double(n) + return ffi.cast('double', n) + end + + local s = box.schema.space.create('test', {engine = 'memtx'}) + s:create_index('pk') + local sk = s:create_index('sk', {parts = { + {1, 'unsigned'}, + {2, 'number', is_nullable = true}, + {3, 'number', is_nullable = true} + }}) + + -- 1-byte unsigned in DB, 8-byte double in request. + s:replace({1, 2}) + t.assert_equals(sk:select({1, double(2), box.NULL}, {iterator = 'EQ'}), + {{1, 2}}) + + -- 8-byte double in DB, 1-byte unsigned in request. + s:replace({1, double(3)}) + t.assert_equals(sk:select({1, 3, box.NULL}, {iterator = 'EQ'}), + {{1, 3}}) + end) +end