mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-06 19: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);
|
rc = mdbx_env_walk(ctx, name, db.md_root, deep + 1);
|
||||||
if (name != namebuf_onstask)
|
if (name != namebuf_onstask)
|
||||||
mdbx_free(name);
|
mdbx_free(name);
|
||||||
|
if (rc == MDBX_SUCCESS && dbi != MDBX_PGWALK_MAIN)
|
||||||
|
rc = MDBX_RESULT_TRUE;
|
||||||
} else {
|
} else {
|
||||||
rc = MDBX_ENOMEM;
|
rc = MDBX_ENOMEM;
|
||||||
}
|
}
|
||||||
@ -13030,9 +13032,12 @@ static int __cold mdbx_env_walk(mdbx_walk_ctx_t *ctx, const char *dbi,
|
|||||||
return MDBX_CORRUPTED;
|
return MDBX_CORRUPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(rc))
|
if (unlikely(rc)) {
|
||||||
|
if (rc == MDBX_RESULT_TRUE)
|
||||||
|
break;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ctx->mw_visitor(mp->mp_pgno, 1, ctx->mw_user, deep, dbi,
|
return ctx->mw_visitor(mp->mp_pgno, 1, ctx->mw_user, deep, dbi,
|
||||||
ctx->mw_txn->mt_env->me_psize, type, nkeys,
|
ctx->mw_txn->mt_env->me_psize, type, nkeys,
|
||||||
|
@ -269,9 +269,11 @@ static int pgvisitor(uint64_t pgno, unsigned pgnumber, void *ctx, int deep,
|
|||||||
walk.pgcount += pgnumber;
|
walk.pgcount += pgnumber;
|
||||||
|
|
||||||
const char *pagetype_caption;
|
const char *pagetype_caption;
|
||||||
|
bool branch = false;
|
||||||
switch (pagetype) {
|
switch (pagetype) {
|
||||||
default:
|
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";
|
pagetype_caption = "unknown";
|
||||||
dbi->pages.other += pgnumber;
|
dbi->pages.other += pgnumber;
|
||||||
break;
|
break;
|
||||||
@ -287,6 +289,7 @@ static int pgvisitor(uint64_t pgno, unsigned pgnumber, void *ctx, int deep,
|
|||||||
case MDBX_page_branch:
|
case MDBX_page_branch:
|
||||||
pagetype_caption = "branch";
|
pagetype_caption = "branch";
|
||||||
dbi->pages.branch += pgnumber;
|
dbi->pages.branch += pgnumber;
|
||||||
|
branch = true;
|
||||||
break;
|
break;
|
||||||
case MDBX_page_leaf:
|
case MDBX_page_leaf:
|
||||||
pagetype_caption = "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)
|
if (unused_bytes > page_size)
|
||||||
problem_add("page", pgno, "illegal unused-bytes",
|
problem_add("page", pgno, "illegal unused-bytes",
|
||||||
"%s-page: %u < %" PRIuPTR " < %u", pagetype_caption, 0,
|
"%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;
|
return user_break ? MDBX_EINTR : MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user