diff options
Diffstat (limited to 'contrib/amcheck/verify_heapam.c')
-rw-r--r-- | contrib/amcheck/verify_heapam.c | 78 |
1 files changed, 53 insertions, 25 deletions
diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c index 37b40a0404d..8bb890438aa 100644 --- a/contrib/amcheck/verify_heapam.c +++ b/contrib/amcheck/verify_heapam.c @@ -105,6 +105,7 @@ typedef struct HeapCheckContext OffsetNumber offnum; ItemId itemid; uint16 lp_len; + uint16 lp_off; HeapTupleHeader tuphdr; int natts; @@ -247,6 +248,13 @@ verify_heapam(PG_FUNCTION_ARGS) memset(&ctx, 0, sizeof(HeapCheckContext)); ctx.cached_xid = InvalidTransactionId; + /* + * If we report corruption when not examining some individual attribute, + * we need attnum to be reported as NULL. Set that up before any + * corruption reporting might happen. + */ + ctx.attnum = -1; + /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */ old_context = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); random_access = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0; @@ -378,14 +386,22 @@ verify_heapam(PG_FUNCTION_ARGS) /* * If this line pointer has been redirected, check that it - * redirects to a valid offset within the line pointer array. + * redirects to a valid offset within the line pointer array */ if (ItemIdIsRedirected(ctx.itemid)) { OffsetNumber rdoffnum = ItemIdGetRedirect(ctx.itemid); ItemId rditem; - if (rdoffnum < FirstOffsetNumber || rdoffnum > maxoff) + if (rdoffnum < FirstOffsetNumber) + { + report_corruption(&ctx, + psprintf("line pointer redirection to item at offset %u precedes minimum offset %u", + (unsigned) rdoffnum, + (unsigned) FirstOffsetNumber)); + continue; + } + if (rdoffnum > maxoff) { report_corruption(&ctx, psprintf("line pointer redirection to item at offset %u exceeds maximum offset %u", @@ -401,8 +417,36 @@ verify_heapam(PG_FUNCTION_ARGS) continue; } - /* Set up context information about this next tuple */ + /* Sanity-check the line pointer's offset and length values */ ctx.lp_len = ItemIdGetLength(ctx.itemid); + ctx.lp_off = ItemIdGetOffset(ctx.itemid); + + if (ctx.lp_off != MAXALIGN(ctx.lp_off)) + { + report_corruption(&ctx, + psprintf("line pointer to page offset %u is not maximally aligned", + ctx.lp_off)); + continue; + } + if (ctx.lp_len < MAXALIGN(SizeofHeapTupleHeader)) + { + report_corruption(&ctx, + psprintf("line pointer length %u is less than the minimum tuple header size %u", + ctx.lp_len, + (unsigned) MAXALIGN(SizeofHeapTupleHeader))); + continue; + } + if (ctx.lp_off + ctx.lp_len > BLCKSZ) + { + report_corruption(&ctx, + psprintf("line pointer to page offset %u with length %u ends beyond maximum page offset %u", + ctx.lp_off, + ctx.lp_len, + (unsigned) BLCKSZ)); + continue; + } + + /* It should be safe to examine the tuple's header, at least */ ctx.tuphdr = (HeapTupleHeader) PageGetItem(ctx.page, ctx.itemid); ctx.natts = HeapTupleHeaderGetNatts(ctx.tuphdr); @@ -1088,25 +1132,6 @@ check_tuple(HeapCheckContext *ctx) bool fatal = false; uint16 infomask = ctx->tuphdr->t_infomask; - /* - * If we report corruption before iterating over individual attributes, we - * need attnum to be reported as NULL. Set that up before any corruption - * reporting might happen. - */ - ctx->attnum = -1; - - /* - * If the line pointer for this tuple does not reserve enough space for a - * complete tuple header, we dare not read the tuple header. - */ - if (ctx->lp_len < MAXALIGN(SizeofHeapTupleHeader)) - { - report_corruption(ctx, - psprintf("line pointer length %u is less than the minimum tuple header size %u", - ctx->lp_len, (uint32) MAXALIGN(SizeofHeapTupleHeader))); - return; - } - /* If xmin is normal, it should be within valid range */ xmin = HeapTupleHeaderGetXmin(ctx->tuphdr); switch (get_xid_status(xmin, ctx, NULL)) @@ -1256,6 +1281,9 @@ check_tuple(HeapCheckContext *ctx) for (ctx->attnum = 0; ctx->attnum < ctx->natts; ctx->attnum++) if (!check_tuple_attribute(ctx)) break; /* cannot continue */ + + /* revert attnum to -1 until we again examine individual attributes */ + ctx->attnum = -1; } /* @@ -1393,9 +1421,9 @@ get_xid_status(TransactionId xid, HeapCheckContext *ctx, if (!fxid_in_cached_range(fxid, ctx)) { /* - * We may have been checking against stale values. Update the - * cached range to be sure, and since we relied on the cached - * range when we performed the full xid conversion, reconvert. + * We may have been checking against stale values. Update the cached + * range to be sure, and since we relied on the cached range when we + * performed the full xid conversion, reconvert. */ update_cached_xid_range(ctx); fxid = FullTransactionIdFromXidAndCtx(xid, ctx); |