mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
amcheck: Add additional TOAST pointer checks.
Expand the checks of toasted attributes to complain if the rawsize is overlarge. For compressed attributes, also complain if compression appears to have expanded the attribute or if the compression method is invalid. Mark Dilger, reviewed by Justin Pryzby, Alexander Alekseev, Heikki Linnakangas, Greg Stark, and me. Discussion: http://postgr.es/m/8E42250D-586A-4A27-B317-8B062C3816A8@enterprisedb.com
This commit is contained in:
parent
db7d1a7b05
commit
bd807be693
@ -30,6 +30,9 @@ PG_FUNCTION_INFO_V1(verify_heapam);
|
|||||||
/* The number of columns in tuples returned by verify_heapam */
|
/* The number of columns in tuples returned by verify_heapam */
|
||||||
#define HEAPCHECK_RELATION_COLS 4
|
#define HEAPCHECK_RELATION_COLS 4
|
||||||
|
|
||||||
|
/* The largest valid toast va_rawsize */
|
||||||
|
#define VARLENA_SIZE_LIMIT 0x3FFFFFFF
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Despite the name, we use this for reporting problems with both XIDs and
|
* Despite the name, we use this for reporting problems with both XIDs and
|
||||||
* MXIDs.
|
* MXIDs.
|
||||||
@ -1414,6 +1417,49 @@ check_tuple_attribute(HeapCheckContext *ctx)
|
|||||||
*/
|
*/
|
||||||
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
|
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
|
||||||
|
|
||||||
|
/* Toasted attributes too large to be untoasted should never be stored */
|
||||||
|
if (toast_pointer.va_rawsize > VARLENA_SIZE_LIMIT)
|
||||||
|
report_corruption(ctx,
|
||||||
|
psprintf("toast value %u rawsize %u exceeds limit %u",
|
||||||
|
toast_pointer.va_valueid,
|
||||||
|
toast_pointer.va_rawsize,
|
||||||
|
VARLENA_SIZE_LIMIT));
|
||||||
|
|
||||||
|
if (VARATT_IS_COMPRESSED(&toast_pointer))
|
||||||
|
{
|
||||||
|
ToastCompressionId cmid;
|
||||||
|
bool valid = false;
|
||||||
|
|
||||||
|
/* Compression should never expand the attribute */
|
||||||
|
if (VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer) > toast_pointer.va_rawsize - VARHDRSZ)
|
||||||
|
report_corruption(ctx,
|
||||||
|
psprintf("toast value %u external size %u exceeds maximum expected for rawsize %u",
|
||||||
|
toast_pointer.va_valueid,
|
||||||
|
VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer),
|
||||||
|
toast_pointer.va_rawsize));
|
||||||
|
|
||||||
|
/* Compressed attributes should have a valid compression method */
|
||||||
|
cmid = TOAST_COMPRESS_METHOD(&toast_pointer);
|
||||||
|
switch (cmid)
|
||||||
|
{
|
||||||
|
/* List of all valid compression method IDs */
|
||||||
|
case TOAST_PGLZ_COMPRESSION_ID:
|
||||||
|
case TOAST_LZ4_COMPRESSION_ID:
|
||||||
|
valid = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Recognized but invalid compression method ID */
|
||||||
|
case TOAST_INVALID_COMPRESSION_ID:
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Intentionally no default here */
|
||||||
|
}
|
||||||
|
if (!valid)
|
||||||
|
report_corruption(ctx,
|
||||||
|
psprintf("toast value %u has invalid compression method id %d",
|
||||||
|
toast_pointer.va_valueid, cmid));
|
||||||
|
}
|
||||||
|
|
||||||
/* The tuple header better claim to contain toasted values */
|
/* The tuple header better claim to contain toasted values */
|
||||||
if (!(infomask & HEAP_HASEXTERNAL))
|
if (!(infomask & HEAP_HASEXTERNAL))
|
||||||
{
|
{
|
||||||
|
@ -218,7 +218,7 @@ my $rel = $node->safe_psql('postgres',
|
|||||||
my $relpath = "$pgdata/$rel";
|
my $relpath = "$pgdata/$rel";
|
||||||
|
|
||||||
# Insert data and freeze public.test
|
# Insert data and freeze public.test
|
||||||
use constant ROWCOUNT => 16;
|
use constant ROWCOUNT => 18;
|
||||||
$node->safe_psql(
|
$node->safe_psql(
|
||||||
'postgres', qq(
|
'postgres', qq(
|
||||||
INSERT INTO public.test (a, b, c)
|
INSERT INTO public.test (a, b, c)
|
||||||
@ -297,7 +297,7 @@ close($file)
|
|||||||
$node->start;
|
$node->start;
|
||||||
|
|
||||||
# Ok, Xids and page layout look ok. We can run corruption tests.
|
# Ok, Xids and page layout look ok. We can run corruption tests.
|
||||||
plan tests => 19;
|
plan tests => 21;
|
||||||
|
|
||||||
# Check that pg_amcheck runs against the uncorrupted table without error.
|
# Check that pg_amcheck runs against the uncorrupted table without error.
|
||||||
$node->command_ok(
|
$node->command_ok(
|
||||||
@ -504,7 +504,7 @@ for (my $tupidx = 0; $tupidx < ROWCOUNT; $tupidx++)
|
|||||||
push @expected,
|
push @expected,
|
||||||
qr/${header}multitransaction ID 4 equals or exceeds next valid multitransaction ID 1/;
|
qr/${header}multitransaction ID 4 equals or exceeds next valid multitransaction ID 1/;
|
||||||
}
|
}
|
||||||
elsif ($offnum == 15) # Last offnum must equal ROWCOUNT
|
elsif ($offnum == 15)
|
||||||
{
|
{
|
||||||
# Set both HEAP_XMAX_COMMITTED and HEAP_XMAX_IS_MULTI
|
# Set both HEAP_XMAX_COMMITTED and HEAP_XMAX_IS_MULTI
|
||||||
$tup->{t_infomask} |= HEAP_XMAX_COMMITTED;
|
$tup->{t_infomask} |= HEAP_XMAX_COMMITTED;
|
||||||
@ -514,6 +514,24 @@ for (my $tupidx = 0; $tupidx < ROWCOUNT; $tupidx++)
|
|||||||
push @expected,
|
push @expected,
|
||||||
qr/${header}multitransaction ID 4000000000 precedes relation minimum multitransaction ID threshold 1/;
|
qr/${header}multitransaction ID 4000000000 precedes relation minimum multitransaction ID threshold 1/;
|
||||||
}
|
}
|
||||||
|
elsif ($offnum == 16)
|
||||||
|
{
|
||||||
|
# Set raw size too large
|
||||||
|
$tup->{c_va_rawsize} = 1073741824;
|
||||||
|
|
||||||
|
$header = header(0, $offnum, 2);
|
||||||
|
push @expected,
|
||||||
|
qr/${header}toast value \d+ rawsize 1073741824 exceeds limit 1073741823/;
|
||||||
|
}
|
||||||
|
elsif ($offnum == 17) # Last offnum should equal ROWCOUNT-1
|
||||||
|
{
|
||||||
|
# Set raw size too small.
|
||||||
|
$tup->{c_va_rawsize} = 9998;
|
||||||
|
|
||||||
|
$header = header(0, $offnum, 2);
|
||||||
|
push @expected,
|
||||||
|
qr/${header}toast value \d+ external size 10000 exceeds maximum expected for rawsize 9998/;
|
||||||
|
}
|
||||||
write_tuple($file, $offset, $tup);
|
write_tuple($file, $offset, $tup);
|
||||||
}
|
}
|
||||||
close($file)
|
close($file)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user