From cb8eec6d11cdab4f7d3cf87913e8009149dcf60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 27 Jan 2025 02:25:32 +0300 Subject: [PATCH] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B3=D1=80=D0=B5=D1=81?= =?UTF-8?q?=D1=81=D0=B0=20=D0=B2=D0=B5=D1=80=D0=BE=D1=8F=D1=82=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20SIGSEGV=20=D0=BF=D1=80=D0=B8=20=D0=B2?= =?UTF-8?q?=D1=8B=D1=82=D0=B5=D1=81=D0=BD=D0=B5=D0=BD=D0=B8=D0=B8/spilling?= =?UTF-8?q?=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ошибка внесена коммитом `a6f7d74a32a3cbcc310916a624a31302dbebfa07` от 2024-03-07 и присутствует в выпусках v0.13.1, v0.13.2, v0.13.3. Проблема оставалась незамеченной из-за специфических условий и низкой вероятности проявления. Суть ошибки: - функция cursor_touch() подготавливает стек страниц курсора к внесению изменений, при этом все страницы в стеке (от корневой до листовой в текущей позиции курсора) должны стать доступными для модификации. - микрооптимизация добавленная коммитом пропускала обход стека, если корневая страница уже доступна для модификации, но это допустимо/корректно только при отсутствии в стеке вытесненных/spilled страниц. - если же складывалась ситуация когда в стека была вытесненная некорневая страница, то она так и оставалась недоступной для записи и при попытке её изменения возникал SIGSEGV. --- src/cursor.c | 2 +- src/node.c | 1 + src/page-get.c | 2 ++ src/spill.c | 10 +++++++--- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index 22442e05..766943f7 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -168,7 +168,7 @@ __hot int cursor_touch(MDBX_cursor *const mc, const MDBX_val *key, const MDBX_va return err; } - if (likely(mc->top >= 0) && !is_modifable(mc->txn, mc->pg[mc->top])) { + if (likely(is_pointed(mc)) && ((mc->txn->flags & MDBX_TXN_SPILLS) || !is_modifable(mc->txn, mc->pg[mc->top]))) { const int8_t top = mc->top; mc->top = 0; do { diff --git a/src/node.c b/src/node.c index f4b264fc..f7676eaf 100644 --- a/src/node.c +++ b/src/node.c @@ -50,6 +50,7 @@ int __must_check_result node_add_branch(MDBX_cursor *mc, size_t indx, const MDBX is_subpage(mp) ? "sub-" : "", mp->pgno, indx, pgno, key ? key->iov_len : 0, DKEY_DEBUG(key)); cASSERT(mc, page_type(mp) == P_BRANCH); + cASSERT(mc, mp->txnid >= mc->txn->front_txnid); STATIC_ASSERT(NODESIZE % 2 == 0); /* Move higher pointers up one slot. */ diff --git a/src/page-get.c b/src/page-get.c index ad3ed3c1..2646eb0e 100644 --- a/src/page-get.c +++ b/src/page-get.c @@ -457,6 +457,8 @@ static __always_inline pgr_t page_get_inline(const uint16_t ILL, const MDBX_curs goto bailout; } + TRACE("dbi %zu, mc %p, page %u, %p", cursor_dbi(mc), __Wpedantic_format_voidptr(mc), pgno, + __Wpedantic_format_voidptr(r.page)); if (unlikely(mc->checking & z_pagecheck)) return check_page_complete(ILL, r.page, mc, front); diff --git a/src/spill.c b/src/spill.c index 29ce8d8a..af09d12d 100644 --- a/src/spill.c +++ b/src/spill.c @@ -72,6 +72,8 @@ static size_t spill_cursor_keep(const MDBX_txn *const txn, const MDBX_cursor *mc intptr_t i = 0; do { mp = mc->pg[i]; + TRACE("dbi %zu, mc-%p[%zu], page %u %p", cursor_dbi(mc), __Wpedantic_format_voidptr(mc), i, mp->pgno, + __Wpedantic_format_voidptr(mp)); tASSERT(txn, !is_subpage(mp)); if (is_modifable(txn, mp)) { size_t const n = dpl_search(txn, mp->pgno); @@ -81,16 +83,18 @@ static size_t spill_cursor_keep(const MDBX_txn *const txn, const MDBX_cursor *mc *ptr = txn->wr.dirtylru; tASSERT(txn, dpl_age(txn, n) == 0); ++keep; + DEBUG("keep page %" PRIaPGNO " (%p), dbi %zu, %scursor %p[%zu]", mp->pgno, __Wpedantic_format_voidptr(mp), + cursor_dbi(mc), is_inner(mc) ? "sub-" : "", __Wpedantic_format_voidptr(mc), i); } } } while (++i <= mc->top); tASSERT(txn, is_leaf(mp)); - if (!mc->subcur || mc->ki[mc->top] >= page_numkeys(mp)) - break; - if (!(node_flags(page_node(mp, mc->ki[mc->top])) & N_TREE)) + if (!inner_pointed(mc)) break; mc = &mc->subcur->cursor; + if (is_subpage(mc->pg[0])) + break; } return keep; }