From cdd510d20e9bea67be8b00af93a3e4bd32450286 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sat, 22 Sep 2018 23:05:04 +0300 Subject: [PATCH] mdbx: backport - prevent DB corruption due rebalance bugs. Won't fix https://github.com/leo-yuriev/libmdbx/issues/38 in the 'stable/0.1' branch, but add checks to prevent DB corruption. --- src/bits.h | 2 ++ src/mdbx.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/bits.h b/src/bits.h index 37d528f4..dd97adf5 100644 --- a/src/bits.h +++ b/src/bits.h @@ -1043,6 +1043,8 @@ static __inline unsigned mdbx_log2(size_t value) { /* Test if a page is a sub page */ #define IS_SUBP(p) F_ISSET((p)->mp_flags, P_SUBP) +#define PAGETYPE(p) ((p)->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW)) + /* The number of overflow pages needed to store the given size. */ #define OVPAGES(env, size) (bytes2pgno(env, PAGEHDRSZ - 1 + (size)) + 1) diff --git a/src/mdbx.c b/src/mdbx.c index ffa2cfbc..b968554f 100644 --- a/src/mdbx.c +++ b/src/mdbx.c @@ -8927,6 +8927,14 @@ static int mdbx_node_move(MDBX_cursor *csrc, MDBX_cursor *cdst, int fromleft) { DKBUF; + mdbx_tassert(csrc->mc_txn, PAGETYPE(csrc->mc_pg[csrc->mc_top]) == + PAGETYPE(cdst->mc_pg[cdst->mc_top])); + if (unlikely(PAGETYPE(csrc->mc_pg[csrc->mc_top]) != + PAGETYPE(cdst->mc_pg[cdst->mc_top]))) { + cdst->mc_txn->mt_flags |= MDBX_TXN_ERROR; + return MDBX_PROBLEM; + } + /* Mark src and dst as dirty. */ if (unlikely((rc = mdbx_page_touch(csrc)) || (rc = mdbx_page_touch(cdst)))) return rc; @@ -9161,6 +9169,12 @@ static int mdbx_page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) { mdbx_cassert(csrc, csrc->mc_snum > 1); /* can't merge root page */ mdbx_cassert(csrc, cdst->mc_snum > 1); + mdbx_tassert(csrc->mc_txn, PAGETYPE(psrc) == PAGETYPE(pdst)); + if (unlikely(PAGETYPE(psrc) != PAGETYPE(pdst))) { + cdst->mc_txn->mt_flags |= MDBX_TXN_ERROR; + return MDBX_PROBLEM; + } + /* Mark dst as dirty. */ if (unlikely(rc = mdbx_page_touch(cdst))) return rc; @@ -9362,7 +9376,7 @@ static int mdbx_rebalance(MDBX_cursor *mc) { m2 = m2->mc_next) { MDBX_cursor *m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2; - if (!(m3->mc_flags & C_INITIALIZED) || (m3->mc_snum < mc->mc_snum)) + if (m3 == mc || !(m3->mc_flags & C_INITIALIZED)) continue; if (m3->mc_pg[0] == mp) { m3->mc_snum = 0;