Skip to content

Commit

Permalink
tuple: fix crash on hashing tuple with double fields
Browse files Browse the repository at this point in the history
`tuple_hash_field()` doesn't advance the MsgPack cursor after hashing
a tuple field with the type `double`, which can result in crashes both
in memtx (while inserting a tuple into a hash index) and in vinyl
(while writing a bloom filter on dump or compaction).

The bug was introduced by commit 51af059 ("box: compare and hash
msgpack value of double key field as double").

Closes #10090

NO_DOC=bug fix

(cherry picked from commit bc0daf9)
  • Loading branch information
locker committed Jun 7, 2024
1 parent 9b8fb7a commit 73dd3a8
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 1 deletion.
6 changes: 6 additions & 0 deletions changelogs/unreleased/gh-10090-tuple-hash-double-fix.md
Original file line number Diff line number Diff line change
@@ -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).
2 changes: 1 addition & 1 deletion src/box/tuple_hash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
37 changes: 37 additions & 0 deletions test/box-luatest/gh_10090_tuple_hash_double_test.lua
Original file line number Diff line number Diff line change
@@ -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
38 changes: 38 additions & 0 deletions test/vinyl-luatest/gh_10090_tuple_hash_double_test.lua
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 73dd3a8

Please sign in to comment.