Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit321633e

Browse files
committed
Fix more portability issues in new amcheck code.
verify_heapam() wasn't being careful to sanity-check tuple linepointers before using them, resulting in SIGBUS on alignment-pickyarchitectures. Fix that, add some more test coverage.Mark Dilger, some tweaking by meDiscussion:https://postgr.es/m/30B8E99A-2D9C-48D4-A55C-741C9D5F1563@enterprisedb.com
1 parent1b62d0f commit321633e

File tree

2 files changed

+73
-35
lines changed

2 files changed

+73
-35
lines changed

‎contrib/amcheck/t/001_verify_heapam.pl

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use PostgresNode;
55
use TestLib;
66

7-
use Test::Moretests=>55;
7+
use Test::Moretests=>79;
88

99
my ($node,$result);
1010

@@ -109,13 +109,17 @@ sub corrupt_first_page
109109
or BAIL_OUT("open failed:$!");
110110
binmode$fh;
111111

112-
# Corrupttwo line pointers.To be stable across platforms, we use
113-
#0x55555555 and 0xAAAAAAAA for the two, which are bitwise reverses of each
114-
#other.
112+
# Corruptsome line pointers.The values are chosen to hit the
113+
#various line-pointer-corruption checks in verify_heapam.c
114+
#on both little-endian and big-endian architectures.
115115
seek($fh, 32, 0)
116116
or BAIL_OUT("seek failed:$!");
117-
syswrite($fh,pack("L*", 0x55555555, 0xAAAAAAAA))
118-
or BAIL_OUT("syswrite failed:$!");
117+
syswrite(
118+
$fh,
119+
pack("L*",
120+
0xAAA15550, 0xAAA0D550, 0x00010000,
121+
0x00008000, 0x0000800F, 0x001e8000)
122+
)or BAIL_OUT("syswrite failed:$!");
119123
close($fh)
120124
or BAIL_OUT("close failed:$!");
121125

@@ -126,17 +130,23 @@ sub detects_heap_corruption
126130
{
127131
my ($function,$testname) =@_;
128132

129-
detects_corruption($function,$testname,
130-
qr/line pointer redirection to item at offset\d+ exceeds maximum offset\d+/
133+
detects_corruption(
134+
$function,
135+
$testname,
136+
qr/line pointer redirection to item at offset\d+ precedes minimum offset\d+/,
137+
qr/line pointer redirection to item at offset\d+ exceeds maximum offset\d+/,
138+
qr/line pointer to page offset\d+ is not maximally aligned/,
139+
qr/line pointer length\d+ is less than the minimum tuple header size\d+/,
140+
qr/line pointer to page offset\d+ with length\d+ ends beyond maximum page offset\d+/,
131141
);
132142
}
133143

134144
subdetects_corruption
135145
{
136-
my ($function,$testname,$re) =@_;
146+
my ($function,$testname,@re) =@_;
137147

138148
my$result =$node->safe_psql('postgres',qq(SELECT * FROM$function));
139-
like($result,$re,$testname);
149+
like($result,$_,$testname)for (@re);
140150
}
141151

142152
subdetects_no_corruption

‎contrib/amcheck/verify_heapam.c

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ typedef struct HeapCheckContext
105105
OffsetNumberoffnum;
106106
ItemIditemid;
107107
uint16lp_len;
108+
uint16lp_off;
108109
HeapTupleHeadertuphdr;
109110
intnatts;
110111

@@ -247,6 +248,13 @@ verify_heapam(PG_FUNCTION_ARGS)
247248
memset(&ctx,0,sizeof(HeapCheckContext));
248249
ctx.cached_xid=InvalidTransactionId;
249250

251+
/*
252+
* If we report corruption when not examining some individual attribute,
253+
* we need attnum to be reported as NULL. Set that up before any
254+
* corruption reporting might happen.
255+
*/
256+
ctx.attnum=-1;
257+
250258
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
251259
old_context=MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
252260
random_access= (rsinfo->allowedModes&SFRM_Materialize_Random)!=0;
@@ -378,14 +386,22 @@ verify_heapam(PG_FUNCTION_ARGS)
378386

379387
/*
380388
* If this line pointer has been redirected, check that it
381-
* redirects to a valid offset within the line pointer array.
389+
* redirects to a valid offset within the line pointer array
382390
*/
383391
if (ItemIdIsRedirected(ctx.itemid))
384392
{
385393
OffsetNumberrdoffnum=ItemIdGetRedirect(ctx.itemid);
386394
ItemIdrditem;
387395

388-
if (rdoffnum<FirstOffsetNumber||rdoffnum>maxoff)
396+
if (rdoffnum<FirstOffsetNumber)
397+
{
398+
report_corruption(&ctx,
399+
psprintf("line pointer redirection to item at offset %u precedes minimum offset %u",
400+
(unsigned)rdoffnum,
401+
(unsigned)FirstOffsetNumber));
402+
continue;
403+
}
404+
if (rdoffnum>maxoff)
389405
{
390406
report_corruption(&ctx,
391407
psprintf("line pointer redirection to item at offset %u exceeds maximum offset %u",
@@ -401,8 +417,36 @@ verify_heapam(PG_FUNCTION_ARGS)
401417
continue;
402418
}
403419

404-
/*Set up context information about this next tuple */
420+
/*Sanity-check the line pointer's offset and length values */
405421
ctx.lp_len=ItemIdGetLength(ctx.itemid);
422+
ctx.lp_off=ItemIdGetOffset(ctx.itemid);
423+
424+
if (ctx.lp_off!=MAXALIGN(ctx.lp_off))
425+
{
426+
report_corruption(&ctx,
427+
psprintf("line pointer to page offset %u is not maximally aligned",
428+
ctx.lp_off));
429+
continue;
430+
}
431+
if (ctx.lp_len<MAXALIGN(SizeofHeapTupleHeader))
432+
{
433+
report_corruption(&ctx,
434+
psprintf("line pointer length %u is less than the minimum tuple header size %u",
435+
ctx.lp_len,
436+
(unsigned)MAXALIGN(SizeofHeapTupleHeader)));
437+
continue;
438+
}
439+
if (ctx.lp_off+ctx.lp_len>BLCKSZ)
440+
{
441+
report_corruption(&ctx,
442+
psprintf("line pointer to page offset %u with length %u ends beyond maximum page offset %u",
443+
ctx.lp_off,
444+
ctx.lp_len,
445+
(unsigned)BLCKSZ));
446+
continue;
447+
}
448+
449+
/* It should be safe to examine the tuple's header, at least */
406450
ctx.tuphdr= (HeapTupleHeader)PageGetItem(ctx.page,ctx.itemid);
407451
ctx.natts=HeapTupleHeaderGetNatts(ctx.tuphdr);
408452

@@ -1088,25 +1132,6 @@ check_tuple(HeapCheckContext *ctx)
10881132
boolfatal= false;
10891133
uint16infomask=ctx->tuphdr->t_infomask;
10901134

1091-
/*
1092-
* If we report corruption before iterating over individual attributes, we
1093-
* need attnum to be reported as NULL. Set that up before any corruption
1094-
* reporting might happen.
1095-
*/
1096-
ctx->attnum=-1;
1097-
1098-
/*
1099-
* If the line pointer for this tuple does not reserve enough space for a
1100-
* complete tuple header, we dare not read the tuple header.
1101-
*/
1102-
if (ctx->lp_len<MAXALIGN(SizeofHeapTupleHeader))
1103-
{
1104-
report_corruption(ctx,
1105-
psprintf("line pointer length %u is less than the minimum tuple header size %u",
1106-
ctx->lp_len, (uint32)MAXALIGN(SizeofHeapTupleHeader)));
1107-
return;
1108-
}
1109-
11101135
/* If xmin is normal, it should be within valid range */
11111136
xmin=HeapTupleHeaderGetXmin(ctx->tuphdr);
11121137
switch (get_xid_status(xmin,ctx,NULL))
@@ -1256,6 +1281,9 @@ check_tuple(HeapCheckContext *ctx)
12561281
for (ctx->attnum=0;ctx->attnum<ctx->natts;ctx->attnum++)
12571282
if (!check_tuple_attribute(ctx))
12581283
break;/* cannot continue */
1284+
1285+
/* revert attnum to -1 until we again examine individual attributes */
1286+
ctx->attnum=-1;
12591287
}
12601288

12611289
/*
@@ -1393,9 +1421,9 @@ get_xid_status(TransactionId xid, HeapCheckContext *ctx,
13931421
if (!fxid_in_cached_range(fxid,ctx))
13941422
{
13951423
/*
1396-
* We may have been checking against stale values. Update the
1397-
*cachedrange to be sure, and since we relied on the cached
1398-
*range when weperformed the full xid conversion, reconvert.
1424+
* We may have been checking against stale values. Update the cached
1425+
* range to be sure, and since we relied on the cached range when we
1426+
* performed the full xid conversion, reconvert.
13991427
*/
14001428
update_cached_xid_range(ctx);
14011429
fxid=FullTransactionIdFromXidAndCtx(xid,ctx);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp