@@ -3697,7 +3697,10 @@ RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup)
36973697 * record (other than to the minimal extent of computing the amount of
36983698 * data to read in) until we've checked the CRCs.
36993699 *
3700- * We assume all of the record has been read into memory at *record.
3700+ * We assume all of the record (that is, xl_tot_len bytes) has been read
3701+ * into memory at *record. Also, ValidXLogRecordHeader() has accepted the
3702+ * record's header, which means in particular that xl_tot_len is at least
3703+ * SizeOfXlogRecord, so it is safe to fetch xl_len.
37013704 */
37023705static bool
37033706RecordIsValid (XLogRecord * record ,XLogRecPtr recptr ,int emode )
@@ -3707,17 +3710,18 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
37073710uint32 len = record -> xl_len ;
37083711BkpBlock bkpb ;
37093712char * blk ;
3710- char * recend = ( char * ) record + record -> xl_tot_len ;
3713+ size_t remaining = record -> xl_tot_len ;
37113714
37123715/* First the rmgr data */
3713- if (XLogRecGetData ( record ) + len > recend )
3716+ if (remaining < SizeOfXLogRecord + len )
37143717{
37153718/* ValidXLogRecordHeader() should've caught this already... */
37163719ereport (emode_for_corrupt_record (emode ,recptr ),
37173720(errmsg ("invalid record length at %X/%X" ,
37183721(uint32 ) (recptr >>32 ), (uint32 )recptr )));
37193722return false;
37203723}
3724+ remaining -= SizeOfXLogRecord + len ;
37213725INIT_CRC32 (crc );
37223726COMP_CRC32 (crc ,XLogRecGetData (record ),len );
37233727
@@ -3730,10 +3734,10 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
37303734if (!(record -> xl_info & XLR_SET_BKP_BLOCK (i )))
37313735continue ;
37323736
3733- if (blk + sizeof (BkpBlock )> recend )
3737+ if (remaining < sizeof (BkpBlock ))
37343738{
37353739ereport (emode_for_corrupt_record (emode ,recptr ),
3736- (errmsg ("incorrect backup block size in record at %X/%X" ,
3740+ (errmsg ("invalid backup block size in record at %X/%X" ,
37373741(uint32 ) (recptr >>32 ), (uint32 )recptr )));
37383742return false;
37393743}
@@ -3748,19 +3752,20 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
37483752}
37493753blen = sizeof (BkpBlock )+ BLCKSZ - bkpb .hole_length ;
37503754
3751- if (blk + blen > recend )
3755+ if (remaining < blen )
37523756{
37533757ereport (emode_for_corrupt_record (emode ,recptr ),
37543758(errmsg ("invalid backup block size in record at %X/%X" ,
37553759(uint32 ) (recptr >>32 ), (uint32 )recptr )));
37563760return false;
37573761}
3762+ remaining -= blen ;
37583763COMP_CRC32 (crc ,blk ,blen );
37593764blk += blen ;
37603765}
37613766
37623767/* Check that xl_tot_len agrees with our calculation */
3763- if (blk != ( char * ) record + record -> xl_tot_len )
3768+ if (remaining != 0 )
37643769{
37653770ereport (emode_for_corrupt_record (emode ,recptr ),
37663771(errmsg ("incorrect total length in record at %X/%X" ,
@@ -3904,8 +3909,11 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
39043909
39053910/*
39063911 * If the whole record header is on this page, validate it immediately.
3907- * Otherwise only do a basic sanity check on xl_tot_len, and validate the
3908- * rest of the header after reading it from the next page.
3912+ * Otherwise do just a basic sanity check on xl_tot_len, and validate the
3913+ * rest of the header after reading it from the next page. The xl_tot_len
3914+ * check is necessary here to ensure that we enter the "Need to reassemble
3915+ * record" code path below; otherwise we might fail to apply
3916+ * ValidXLogRecordHeader at all.
39093917 */
39103918if (targetRecOff <=XLOG_BLCKSZ - SizeOfXLogRecord )
39113919{