Skip to content

Commit 80d5e3a

Browse files
committed
amcheck: Tighten up validation of redirect line pointers.
Commit bbc1376 added a new lp_valid[] array which records whether or not a line pointer was thought to be valid, but entries could sometimes get set to true in cases where that wasn't actually safe. Fix that. Suppose A is a redirect line pointer and B is the other line pointer to which it points. The old code could mishandle this situation in a couple of different ways. First, if B was unused, we'd complain about corruption but still set lp_valid[A] = true, causing later code to try to access the B as if it were pointing to a tuple. Second, if B was dead, we wouldn't complain about corruption at all, which is an oversight, and would also set lp_valid[A] = true, which would again confuse later code. Fix all that. In the case where B is a redirect, the old code was correct, but refactor things a bit anyway so that all of these cases are handled more symmetrically. Also add an Assert() and some comments. Andres Freund and Robert Haas Discussion: http://postgr.es/m/20230323172607.y3lejpntjnuis5vv%40awork3.anarazel.de
1 parent 5a91c79 commit 80d5e3a

File tree

1 file changed

+31
-9
lines changed

1 file changed

+31
-9
lines changed

contrib/amcheck/verify_heapam.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -481,11 +481,35 @@ verify_heapam(PG_FUNCTION_ARGS)
481481
(unsigned) maxoff));
482482
continue;
483483
}
484+
485+
/*
486+
* Since we've checked that this redirect points to a line
487+
* pointer between FirstOffsetNumber and maxoff, it should
488+
* now be safe to fetch the referenced line pointer. We expect
489+
* it to be LP_NORMAL; if not, that's corruption.
490+
*/
484491
rditem = PageGetItemId(ctx.page, rdoffnum);
485492
if (!ItemIdIsUsed(rditem))
493+
{
486494
report_corruption(&ctx,
487-
psprintf("line pointer redirection to unused item at offset %u",
495+
psprintf("redirected line pointer points to an unused item at offset %u",
488496
(unsigned) rdoffnum));
497+
continue;
498+
}
499+
else if (ItemIdIsDead(rditem))
500+
{
501+
report_corruption(&ctx,
502+
psprintf("redirected line pointer points to a dead item at offset %u",
503+
(unsigned) rdoffnum));
504+
continue;
505+
}
506+
else if (ItemIdIsRedirected(rditem))
507+
{
508+
report_corruption(&ctx,
509+
psprintf("redirected line pointer points to another redirected line pointer at offset %u",
510+
(unsigned) rdoffnum));
511+
continue;
512+
}
489513

490514
/*
491515
* Record the fact that this line pointer has passed basic
@@ -584,14 +608,12 @@ verify_heapam(PG_FUNCTION_ARGS)
584608
/* Handle the cases where the current line pointer is a redirect. */
585609
if (ItemIdIsRedirected(curr_lp))
586610
{
587-
/* Can't redirect to another redirect. */
588-
if (ItemIdIsRedirected(next_lp))
589-
{
590-
report_corruption(&ctx,
591-
psprintf("redirected line pointer points to another redirected line pointer at offset %u",
592-
(unsigned) nextoffnum));
593-
continue;
594-
}
611+
/*
612+
* We should not have set successor[ctx.offnum] to a value
613+
* other than InvalidOffsetNumber unless that line pointer
614+
* is LP_NORMAL.
615+
*/
616+
Assert(ItemIdIsNormal(next_lp));
595617

596618
/* Can only redirect to a HOT tuple. */
597619
next_htup = (HeapTupleHeader) PageGetItem(ctx.page, next_lp);

0 commit comments

Comments
 (0)