diff --git a/changelogs/unreleased/gh-10090-tuple-hash-double-fix.md b/changelogs/unreleased/gh-10090-tuple-hash-double-fix.md new file mode 100644 index 0000000000000000000000000000000000000000..7d4023565ae3528f045def5ae879d3b997c5a49d --- /dev/null +++ b/changelogs/unreleased/gh-10090-tuple-hash-double-fix.md @@ -0,0 +1,6 @@ +## bugfix/core + +* Fixed a bug when hashing a tuple with `double` fields could crash. + The bug could trigger a crash in memtx while inserting a tuple into + a `hash` index and in vinyl while writing a bloom filter on dump or + compaction (gh-10090). diff --git a/src/box/tuple_hash.cc b/src/box/tuple_hash.cc index 1c921dda125a72f3a10d3c0b76cd6f90aaa2cb23..4e8e2bac4581e1976e99fc302c5a9dc9f1f8562e 100644 --- a/src/box/tuple_hash.cc +++ b/src/box/tuple_hash.cc @@ -313,7 +313,7 @@ tuple_hash_field(uint32_t *ph1, uint32_t *pcarry, const char **field, * This will only fail if the mp_type is not numeric, which is * impossible here (see field_mp_plain_type_is_compatible). */ - if (mp_read_double_lossy(&f, &value) == -1) + if (mp_read_double_lossy(field, &value) == -1) unreachable(); char *double_msgpack_end = mp_encode_double(buf, value); size = double_msgpack_end - buf; diff --git a/test/box-luatest/gh_10090_tuple_hash_double_test.lua b/test/box-luatest/gh_10090_tuple_hash_double_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..141587be995332ac5d8785a68180abd208a41748 --- /dev/null +++ b/test/box-luatest/gh_10090_tuple_hash_double_test.lua @@ -0,0 +1,37 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group() + +g.before_all(function(cg) + cg.server = server:new() + cg.server:start() +end) + +g.after_all(function(cg) + cg.server:drop() +end) + +g.after_each(function(cg) + cg.server:exec(function() + if box.space.test ~= nil then + box.space.test:drop() + end + end) +end) + +g.test_tuple_hash_double = function(cg) + cg.server:exec(function() + local s = box.schema.create_space('test') + s:create_index('pk', { + type = 'hash', + parts = { + {1, 'double'}, {2, 'string'}, {3, 'double'}, + }, + }) + s:insert{1, 'x', 0.5} + s:insert{0.5, 'y', 1} + s:delete{0.5, 'y', 1} + t.assert_equals(s:select({}, {fullscan = true}), {{1, 'x', 0.5}}) + end) +end diff --git a/test/vinyl-luatest/gh_10090_tuple_hash_double_test.lua b/test/vinyl-luatest/gh_10090_tuple_hash_double_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..f75a83864c3a1678869565c463ad1e536b737818 --- /dev/null +++ b/test/vinyl-luatest/gh_10090_tuple_hash_double_test.lua @@ -0,0 +1,38 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group() + +g.before_all(function(cg) + cg.server = server:new() + cg.server:start() +end) + +g.after_all(function(cg) + cg.server:drop() +end) + +g.after_each(function(cg) + cg.server:exec(function() + if box.space.test ~= nil then + box.space.test:drop() + end + end) +end) + +g.test_tuple_hash_double = function(cg) + cg.server:exec(function() + local s = box.schema.create_space('test', {engine = 'vinyl'}) + s:create_index('pk', { + parts = { + {1, 'double'}, {2, 'string'}, {3, 'double'}, + }, + }) + s:insert{1, 'x', 0.5} + s:insert{0.5, 'y', 1} + box.snapshot() + s:delete{0.5, 'y', 1} + box.snapshot() + t.assert_equals(s:select({}, {fullscan = true}), {{1, 'x', 0.5}}) + end) +end