diff --git a/src/mdbx.c b/src/mdbx.c index 999a95ab..40737d7f 100644 --- a/src/mdbx.c +++ b/src/mdbx.c @@ -12963,6 +12963,8 @@ static int __cold mdbx_env_walk(mdbx_walk_ctx_t *ctx, const char *dbi, rc = mdbx_env_walk(ctx, name, db.md_root, deep + 1); if (name != namebuf_onstask) mdbx_free(name); + if (rc == MDBX_SUCCESS && dbi != MDBX_PGWALK_MAIN) + rc = MDBX_RESULT_TRUE; } else { rc = MDBX_ENOMEM; } @@ -13030,8 +13032,11 @@ static int __cold mdbx_env_walk(mdbx_walk_ctx_t *ctx, const char *dbi, return MDBX_CORRUPTED; } - if (unlikely(rc)) + if (unlikely(rc)) { + if (rc == MDBX_RESULT_TRUE) + break; return rc; + } } return ctx->mw_visitor(mp->mp_pgno, 1, ctx->mw_user, deep, dbi, diff --git a/src/tools/mdbx_chk.c b/src/tools/mdbx_chk.c index 343efe94..21ab2eeb 100644 --- a/src/tools/mdbx_chk.c +++ b/src/tools/mdbx_chk.c @@ -269,9 +269,11 @@ static int pgvisitor(uint64_t pgno, unsigned pgnumber, void *ctx, int deep, walk.pgcount += pgnumber; const char *pagetype_caption; + bool branch = false; switch (pagetype) { default: - problem_add("page", pgno, "unknown page-type", "%u", (unsigned)pagetype); + problem_add("page", pgno, "unknown page-type", "type %u, deep %i", + (unsigned)pagetype, deep); pagetype_caption = "unknown"; dbi->pages.other += pgnumber; break; @@ -287,6 +289,7 @@ static int pgvisitor(uint64_t pgno, unsigned pgnumber, void *ctx, int deep, case MDBX_page_branch: pagetype_caption = "branch"; dbi->pages.branch += pgnumber; + branch = true; break; case MDBX_page_leaf: pagetype_caption = "leaf"; @@ -318,6 +321,36 @@ static int pgvisitor(uint64_t pgno, unsigned pgnumber, void *ctx, int deep, } } + if (pgnumber) { + bool already_used = false; + do { + if (pgno >= lastpgno) + problem_add("page", pgno, "wrong page-no", + "%s-page: %" PRIu64 " > %" PRIu64 ", deep %i", + pagetype_caption, pgno, lastpgno, deep); + else if (walk.pagemap[pgno]) { + walk_dbi_t *coll_dbi = &walk.dbi[walk.pagemap[pgno] - 1]; + problem_add( + "page", pgno, (branch && coll_dbi == dbi) ? "loop" : "already used", + "%s-page: by %s, deep %i", pagetype_caption, coll_dbi->name, deep); + already_used = true; + } else { + walk.pagemap[pgno] = (short)(dbi - walk.dbi + 1); + dbi->pages.total += 1; + } + ++pgno; + } while (--pgnumber); + + if (already_used) + return branch ? MDBX_RESULT_TRUE /* avoid infinite loop/recursion */ + : MDBX_SUCCESS; + + if (deep > 42) { + problem_add("deep", deep, "too large", nullptr); + return MDBX_CORRUPTED /* avoid infinite loop/recursion */; + } + } + if (unused_bytes > page_size) problem_add("page", pgno, "illegal unused-bytes", "%s-page: %u < %" PRIuPTR " < %u", pagetype_caption, 0, @@ -362,23 +395,6 @@ static int pgvisitor(uint64_t pgno, unsigned pgnumber, void *ctx, int deep, } } - if (pgnumber) { - do { - if (pgno >= lastpgno) - problem_add("page", pgno, "wrong page-no", - "%s-page: %" PRIu64 " > %" PRIu64, pagetype_caption, pgno, - lastpgno); - else if (walk.pagemap[pgno]) - problem_add("page", pgno, "already used", "%s-page: by %s", - pagetype_caption, walk.dbi[walk.pagemap[pgno] - 1].name); - else { - walk.pagemap[pgno] = (short)(dbi - walk.dbi + 1); - dbi->pages.total += 1; - } - ++pgno; - } while (--pgnumber); - } - return user_break ? MDBX_EINTR : MDBX_SUCCESS; }