Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit becfbdd

Browse files
committed
Fix edge-case for xl_tot_len broken by bae868c.
bae868c removed a check that was still needed. If you had an xl_tot_len at the end of a page that was too small for a record header, but not big enough to span onto the next page, we'd immediately perform the CRC check using a bogus large length. Because of arbitrary coding differences between the CRC implementations on different platforms, nothing very bad happened on common modern systems. On systems using the _sb8.c fallback we could segfault. Restore that check, add a new assertion and supply a test for that case. Back-patch to 12, like bae868c. Tested-by: Tom Lane <tgl@sss.pgh.pa.us> Tested-by: Alexander Lakhin <exclusion@gmail.com> Discussion: https://postgr.es/m/CA%2BhUKGLCkTT7zYjzOxuLGahBdQ%3DMcF%3Dz5ZvrjSOnW4EDhVjT-g%40mail.gmail.com
1 parent 13aeaf0 commit becfbdd

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

src/backend/access/transam/xlogreader.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,15 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
653653
}
654654
else
655655
{
656+
/* There may be no next page if it's too small. */
657+
if (total_len < SizeOfXLogRecord)
658+
{
659+
report_invalid_record(state,
660+
"invalid record length at %X/%X: expected at least %u, got %u",
661+
LSN_FORMAT_ARGS(RecPtr),
662+
(uint32) SizeOfXLogRecord, total_len);
663+
goto err;
664+
}
656665
/* We'll validate the header once we have the next page. */
657666
gotheader = false;
658667
}
@@ -1190,6 +1199,8 @@ ValidXLogRecord(XLogReaderState *state, XLogRecord *record, XLogRecPtr recptr)
11901199
{
11911200
pg_crc32c crc;
11921201

1202+
Assert(record->xl_tot_len >= SizeOfXLogRecord);
1203+
11931204
/* Calculate the CRC */
11941205
INIT_CRC32C(crc);
11951206
COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);

src/test/recovery/t/039_end_of_wal.pl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,19 @@ sub advance_to_record_splitting_zone
281281
$log_size),
282282
"xl_tot_len short");
283283

284+
# xl_tot_len in final position, not big enough to span into a new page but
285+
# also not eligible for regular record header validation
286+
emit_message($node, 0);
287+
$end_lsn = advance_to_record_splitting_zone($node);
288+
$node->stop('immediate');
289+
write_wal($node, $TLI, $end_lsn, build_record_header(1));
290+
$log_size = -s $node->logfile;
291+
$node->start;
292+
ok( $node->log_contains(
293+
"invalid record length at .*: expected at least 24, got 1", $log_size
294+
),
295+
"xl_tot_len short at end-of-page");
296+
284297
# Need more pages, but xl_prev check fails first.
285298
emit_message($node, 0);
286299
$end_lsn = advance_out_of_record_splitting_zone($node);

0 commit comments

Comments
 (0)