mdbx-chk: avoid infinite loop/recursion while checking corrupted DB.

Change-Id: I3edb053e4baedced8ce8e8cfa25f9851eaca35d1
This commit is contained in:
Leonid Yuriev 2019-06-19 14:47:26 +03:00
parent c05702eacf
commit 2bea60a1a4
2 changed files with 40 additions and 19 deletions

View File

@ -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,

View File

@ -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;
}