mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-02 00:04:12 +08:00
mdbx-chk: avoid infinite loop/recursion while checking corrupted DB.
Change-Id: I3edb053e4baedced8ce8e8cfa25f9851eaca35d1
This commit is contained in:
parent
c05702eacf
commit
2bea60a1a4
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user