mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Fix edge-case for xl_tot_len broken by bae868ca.
				
					
				
			bae868caremoved 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, likebae868ca. 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
This commit is contained in:
		@@ -380,6 +380,15 @@ restart:
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							/* There may be no next page if it's too small. */
 | 
				
			||||||
 | 
							if (total_len < SizeOfXLogRecord)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								report_invalid_record(state,
 | 
				
			||||||
 | 
													  "invalid record length at %X/%X: wanted %u, got %u",
 | 
				
			||||||
 | 
													  LSN_FORMAT_ARGS(RecPtr),
 | 
				
			||||||
 | 
													  (uint32) SizeOfXLogRecord, total_len);
 | 
				
			||||||
 | 
								goto err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		/* We'll validate the header once we have the next page. */
 | 
							/* We'll validate the header once we have the next page. */
 | 
				
			||||||
		gotheader = false;
 | 
							gotheader = false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -792,6 +801,8 @@ ValidXLogRecord(XLogReaderState *state, XLogRecord *record, XLogRecPtr recptr)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	pg_crc32c	crc;
 | 
						pg_crc32c	crc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Assert(record->xl_tot_len >= SizeOfXLogRecord);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Calculate the CRC */
 | 
						/* Calculate the CRC */
 | 
				
			||||||
	INIT_CRC32C(crc);
 | 
						INIT_CRC32C(crc);
 | 
				
			||||||
	COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
 | 
						COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -287,6 +287,19 @@ ok( $node->log_contains(
 | 
				
			|||||||
		$log_size),
 | 
							$log_size),
 | 
				
			||||||
	"xl_tot_len short");
 | 
						"xl_tot_len short");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# xl_tot_len in final position, not big enough to span into a new page but
 | 
				
			||||||
 | 
					# also not eligible for regular record header validation
 | 
				
			||||||
 | 
					emit_message($node, 0);
 | 
				
			||||||
 | 
					$end_lsn = advance_to_record_splitting_zone($node);
 | 
				
			||||||
 | 
					$node->stop('immediate');
 | 
				
			||||||
 | 
					write_wal($node, $TLI, $end_lsn, build_record_header(1));
 | 
				
			||||||
 | 
					$log_size = -s $node->logfile;
 | 
				
			||||||
 | 
					$node->start;
 | 
				
			||||||
 | 
					ok( $node->log_contains(
 | 
				
			||||||
 | 
							"invalid record length at .*: wanted 24, got 1", $log_size
 | 
				
			||||||
 | 
						),
 | 
				
			||||||
 | 
						"xl_tot_len short at end-of-page");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Need more pages, but xl_prev check fails first.
 | 
					# Need more pages, but xl_prev check fails first.
 | 
				
			||||||
emit_message($node, 0);
 | 
					emit_message($node, 0);
 | 
				
			||||||
$end_lsn = advance_out_of_record_splitting_zone($node);
 | 
					$end_lsn = advance_out_of_record_splitting_zone($node);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user