Skip to content

Commit 4731d84

Browse files
committed
pg_controldata: Prevent division-by-zero errors
If the control file is corrupted and specifies the WAL segment size to be 0 bytes, calculating the latest checkpoint's REDO WAL file will fail with a division-by-zero error. Show it as "???" instead. Also reword the warning message a bit and send it to stdout, like the other pre-existing warning messages. Add some tests for dealing with a corrupted pg_control file. Author: Nathan Bossart <bossartn@amazon.com>, tests by me
1 parent 5616300 commit 4731d84

File tree

2 files changed

+38
-9
lines changed

2 files changed

+38
-9
lines changed

src/bin/pg_controldata/pg_controldata.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ main(int argc, char *argv[])
9595
char mock_auth_nonce_str[MOCK_AUTH_NONCE_LEN * 2 + 1];
9696
const char *strftime_fmt = "%c";
9797
const char *progname;
98-
XLogSegNo segno;
9998
char xlogfilename[MAXFNAMELEN];
10099
int c;
101100
int i;
@@ -169,10 +168,11 @@ main(int argc, char *argv[])
169168
WalSegSz = ControlFile->xlog_seg_size;
170169

171170
if (!IsValidWalSegSize(WalSegSz))
172-
fprintf(stderr,
173-
_("WARNING: WAL segment size specified, %d bytes, is not a power of two between 1MB and 1GB.\n"
174-
"The file is corrupt and the results below are untrustworthy.\n"),
175-
WalSegSz);
171+
printf(_("WARNING: invalid WAL segment size\n"
172+
"The WAL segment size stored in the file, %d bytes, is not a power of two\n"
173+
"between 1 MB and 1 GB. The file is corrupt and the results below are\n"
174+
"untrustworthy.\n\n"),
175+
WalSegSz);
176176

177177
/*
178178
* This slightly-chintzy coding will work as long as the control file
@@ -193,10 +193,20 @@ main(int argc, char *argv[])
193193
/*
194194
* Calculate name of the WAL file containing the latest checkpoint's REDO
195195
* start point.
196+
*
197+
* A corrupted control file could report a WAL segment size of 0, and to
198+
* guard against division by zero, we need to treat that specially.
196199
*/
197-
XLByteToSeg(ControlFile->checkPointCopy.redo, segno, WalSegSz);
198-
XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
199-
segno, WalSegSz);
200+
if (WalSegSz != 0)
201+
{
202+
XLogSegNo segno;
203+
204+
XLByteToSeg(ControlFile->checkPointCopy.redo, segno, WalSegSz);
205+
XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
206+
segno, WalSegSz);
207+
}
208+
else
209+
strcpy(xlogfilename, _("???"));
200210

201211
/*
202212
* Format system_identifier and mock_authentication_nonce separately to

src/bin/pg_controldata/t/001_pg_controldata.pl

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use warnings;
33
use PostgresNode;
44
use TestLib;
5-
use Test::More tests => 13;
5+
use Test::More tests => 17;
66

77
program_help_ok('pg_controldata');
88
program_version_ok('pg_controldata');
@@ -16,3 +16,22 @@
1616

1717
command_like([ 'pg_controldata', $node->data_dir ],
1818
qr/checkpoint/, 'pg_controldata produces output');
19+
20+
21+
# check with a corrupted pg_control
22+
23+
my $pg_control = $node->data_dir . '/global/pg_control';
24+
my $size = (stat($pg_control))[7];
25+
26+
open my $fh, '>', $pg_control or BAIL_OUT($!);
27+
binmode $fh;
28+
# fill file with zeros
29+
print $fh pack("x[$size]");
30+
close $fh;
31+
32+
command_checks_all([ 'pg_controldata', $node->data_dir ],
33+
0,
34+
[ qr/WARNING: Calculated CRC checksum does not match value stored in file/,
35+
qr/WARNING: invalid WAL segment size/ ],
36+
[ qr/^$/ ],
37+
'pg_controldata with corrupted pg_control');

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy