From 6627d14edf1eddb4da1765f1c5c503003ce01d77 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: Wed, 23 Apr 2025 23:26:57 +0300 Subject: [PATCH] =?UTF-8?q?mdbx:=20=D1=83=D0=BF=D1=80=D0=BE=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=81=D1=82=D0=B0=D1=80=D1=82=D0=B0=20?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=B8=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20double-free=20=D0=BF=D1=80=D0=B8=20=D0=BE?= =?UTF-8?q?=D1=88=D0=B8=D0=B1=D0=BA=D0=B5=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=B2=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20=D1=82=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-txn.c | 51 ++++++++++++++++++++++++------------------------ src/txn-nested.c | 47 ++++++++++++++++++++------------------------ 2 files changed, 47 insertions(+), 51 deletions(-) diff --git a/src/api-txn.c b/src/api-txn.c index 04feabea..847d8f9e 100644 --- a/src/api-txn.c +++ b/src/api-txn.c @@ -235,9 +235,11 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, M flags |= parent->flags & (txn_rw_begin_flags | MDBX_TXN_SPILLS | MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP); rc = txn_nested_create(parent, flags); txn = parent->nested; - if (unlikely(rc != MDBX_SUCCESS)) - txn_end(txn, TXN_END_FAIL_BEGIN_NESTED); - else if (AUDIT_ENABLED() && ASSERT_ENABLED()) { + if (unlikely(rc != MDBX_SUCCESS)) { + int err = txn_end(txn, TXN_END_FAIL_BEGIN_NESTED); + return err ? err : rc; + } + if (AUDIT_ENABLED() && ASSERT_ENABLED()) { txn->signature = txn_signature; tASSERT(txn, audit_ex(txn, 0, false) == 0); } @@ -249,31 +251,30 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, M return LOG_IFERR(MDBX_ENOMEM); } rc = txn_renew(txn, flags); - } - - if (unlikely(rc != MDBX_SUCCESS)) { - if (txn != env->basal_txn) - osal_free(txn); - } else { - if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY)) - eASSERT(env, txn->flags == (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED)); - else if (flags & MDBX_TXN_RDONLY) - eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_TXN_RDONLY | MDBX_WRITEMAP | - /* Win32: SRWL flag */ txn_shrink_allowed)) == 0); - else { - eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP | txn_shrink_allowed | txn_may_have_cursors | - MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC | MDBX_TXN_SPILLS)) == 0); - assert(!txn->wr.spilled.list && !txn->wr.spilled.least_removed); + if (unlikely(rc != MDBX_SUCCESS)) { + if (txn != env->basal_txn) + osal_free(txn); + return LOG_IFERR(rc); } - txn->signature = txn_signature; - txn->userctx = context; - *ret = txn; - DEBUG("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, txn->txnid, - (flags & MDBX_TXN_RDONLY) ? 'r' : 'w', (void *)txn, (void *)env, txn->dbs[MAIN_DBI].root, - txn->dbs[FREE_DBI].root); } - return LOG_IFERR(rc); + if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY)) + eASSERT(env, txn->flags == (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED)); + else if (flags & MDBX_TXN_RDONLY) + eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_TXN_RDONLY | MDBX_WRITEMAP | + /* Win32: SRWL flag */ txn_shrink_allowed)) == 0); + else { + eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP | txn_shrink_allowed | txn_may_have_cursors | + MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC | MDBX_TXN_SPILLS)) == 0); + assert(!txn->wr.spilled.list && !txn->wr.spilled.least_removed); + } + txn->signature = txn_signature; + txn->userctx = context; + *ret = txn; + DEBUG("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, txn->txnid, + (flags & MDBX_TXN_RDONLY) ? 'r' : 'w', (void *)txn, (void *)env, txn->dbs[MAIN_DBI].root, + txn->dbs[FREE_DBI].root); + return MDBX_SUCCESS; } static void latency_gcprof(MDBX_commit_latency *latency, const MDBX_txn *txn) { diff --git a/src/txn-nested.c b/src/txn-nested.c index c6c728f1..57a04de7 100644 --- a/src/txn-nested.c +++ b/src/txn-nested.c @@ -348,25 +348,30 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) { return LOG_IFERR(MDBX_ENOMEM); tASSERT(parent, dpl_check(parent)); + txn->txnid = parent->txnid; + txn->front_txnid = parent->front_txnid + 1; + txn->canary = parent->canary; + parent->flags |= MDBX_TXN_HAS_CHILD; + parent->nested = txn; + txn->parent = parent; + txn->env->txn = txn; + txn->owner = parent->owner; + txn->wr.troika = parent->wr.troika; + #if MDBX_ENABLE_DBI_SPARSE txn->dbi_sparse = parent->dbi_sparse; #endif /* MDBX_ENABLE_DBI_SPARSE */ txn->dbi_seqs = parent->dbi_seqs; txn->geo = parent->geo; + int err = dpl_alloc(txn); - if (likely(err == MDBX_SUCCESS)) { - const size_t len = MDBX_PNL_GETSIZE(parent->wr.repnl) + parent->wr.loose_count; - txn->wr.repnl = pnl_alloc((len > MDBX_PNL_INITIAL) ? len : MDBX_PNL_INITIAL); - if (unlikely(!txn->wr.repnl)) - err = MDBX_ENOMEM; - } - if (unlikely(err != MDBX_SUCCESS)) { - failed: - pnl_free(txn->wr.repnl); - dpl_free(txn); - osal_free(txn); + if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); - } + + const size_t len = MDBX_PNL_GETSIZE(parent->wr.repnl) + parent->wr.loose_count; + txn->wr.repnl = pnl_alloc((len > MDBX_PNL_INITIAL) ? len : MDBX_PNL_INITIAL); + if (unlikely(!txn->wr.repnl)) + return LOG_IFERR(MDBX_ENOMEM); /* Move loose pages to reclaimed list */ if (parent->wr.loose_count) { @@ -375,7 +380,7 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) { tASSERT(parent, lp->flags == P_LOOSE); err = pnl_insert_span(&parent->wr.repnl, lp->pgno, 1); if (unlikely(err != MDBX_SUCCESS)) - goto failed; + return LOG_IFERR(err); MDBX_ASAN_UNPOISON_MEMORY_REGION(&page_next(lp), sizeof(page_t *)); VALGRIND_MAKE_MEM_DEFINED(&page_next(lp), sizeof(page_t *)); parent->wr.loose_pages = page_next(lp); @@ -388,6 +393,9 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) { #endif /* MDBX_ENABLE_REFUND */ tASSERT(parent, dpl_check(parent)); } +#if MDBX_ENABLE_REFUND + txn->wr.loose_refund_wl = 0; +#endif /* MDBX_ENABLE_REFUND */ txn->wr.dirtyroom = parent->wr.dirtyroom; txn->wr.dirtylru = parent->wr.dirtylru; @@ -412,18 +420,6 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) { txn->wr.retired_pages = parent->wr.retired_pages; parent->wr.retired_pages = (void *)(intptr_t)MDBX_PNL_GETSIZE(parent->wr.retired_pages); - txn->txnid = parent->txnid; - txn->front_txnid = parent->front_txnid + 1; -#if MDBX_ENABLE_REFUND - txn->wr.loose_refund_wl = 0; -#endif /* MDBX_ENABLE_REFUND */ - txn->canary = parent->canary; - parent->flags |= MDBX_TXN_HAS_CHILD; - parent->nested = txn; - txn->parent = parent; - txn->owner = parent->owner; - txn->wr.troika = parent->wr.troika; - txn->cursors[FREE_DBI] = nullptr; txn->cursors[MAIN_DBI] = nullptr; txn->dbi_state[FREE_DBI] = parent->dbi_state[FREE_DBI] & ~(DBI_FRESH | DBI_CREAT | DBI_DIRTY); @@ -435,7 +431,6 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) { (parent->parent ? parent->parent->wr.dirtyroom : parent->env->options.dp_limit)); tASSERT(txn, txn->wr.dirtyroom + txn->wr.dirtylist->length == (txn->parent ? txn->parent->wr.dirtyroom : txn->env->options.dp_limit)); - parent->env->txn = txn; tASSERT(parent, parent->cursors[FREE_DBI] == nullptr); return txn_shadow_cursors(parent, MAIN_DBI); }