commit e0a9aed47b2fdef34db0bccf8a81b91e4b17e65f from: Ilya Verbin via: Vladimir Davydov date: Fri Oct 28 07:43:33 2022 UTC box: panic if snapshot has no system spaces during recovery Currently, if a snapshot contains some correct entries, but doesn't include system spaces, Tarantool crashes with segmentation fault, or for Debug build: void diag_raise(): Assertion `e != NULL' failed. This happens because memtx_engine_recover_snapshot returns -1, while diag is not set. Let's panic instead of a crash. Closes #7800 NO_DOC=bugfix commit - 55e3bb3b9202bcec83dec59d6a08ff4a793f99c8 commit + e0a9aed47b2fdef34db0bccf8a81b91e4b17e65f blob - /dev/null blob + 8da90191e6e1675b6ae95f3e6be1f66dbdca0e02 (mode 644) --- /dev/null +++ changelogs/unreleased/gh-7800-recover-snap-without-spaces.md @@ -0,0 +1,4 @@ +## bugfix/box + +* Fixed a crash on recovery from a snapshot, which doesn't include system spaces + (gh-7800). blob - faca74651fff09b70dfc09cac71fe25a8dad27fd blob + 3b4e37964c2c0147de5e887f133940001cd3fb85 --- src/box/memtx_engine.cc +++ src/box/memtx_engine.cc @@ -263,7 +263,7 @@ memtx_engine_recover_snapshot(struct memtx_engine *mem } } xlog_cursor_close(&cursor, false); - if (rc < 0 || is_space_system < 0) + if (rc < 0) return -1; /** @@ -278,6 +278,13 @@ memtx_engine_recover_snapshot(struct memtx_engine *mem say_error("snapshot `%s' has no EOF marker", cursor.name); } + /* + * Snapshot entries are ordered by the space id, it means that if there + * are no spaces, then all system spaces are definitely missing. + */ + if (is_space_system < 0) + panic("snapshot `%s' has no system spaces", cursor.name); + return 0; } blob - /dev/null blob + 7dc1f61d242d67cd7db4f553b15866650f69e547 (mode 644) Binary files /dev/null and test/box-luatest/gh_7800_data/00000000000000000000.snap differ blob - /dev/null blob + e4871f3b6f67b8bab925561c36fc90992df6390e (mode 644) --- /dev/null +++ test/box-luatest/gh_7800_recover_snap_without_spaces_test.lua @@ -0,0 +1,23 @@ +local t = require('luatest') +local g = t.group('gh-7800') + +g.before_all(function() + local server = require('test.luatest_helpers.server') + g.server = server:new({alias = 'master', + datadir = 'test/box-luatest/gh_7800_data'}) + g.server:start({wait_for_readiness = false}) +end) + +g.after_all(function() + g.server:cleanup() +end) + +g.test_recovery = function() + t.helpers.retrying({}, function() + local fio = require('fio') + local msg = "has no system spaces" + local filename = fio.pathjoin(g.server.workdir, + g.server.alias .. '.log') + t.assert(g.server:grep_log(msg, nil, {filename = filename})) + end) +end