aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2018-03-21 12:14:53 -0400
committerPeter Eisentraut <peter_e@gmx.net>2018-03-21 12:21:23 -0400
commit4731d848f23e08a9396b4831d13fbb6dd460faf2 (patch)
tree006382f6eb95b692556b818f5a9e7ef07cbb5153 /src
parent56163004b8b2151db279744b77138d4d90e2d5cb (diff)
downloadpostgresql-4731d848f23e08a9396b4831d13fbb6dd460faf2.tar.gz
postgresql-4731d848f23e08a9396b4831d13fbb6dd460faf2.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/bin/pg_controldata/pg_controldata.c26
-rw-r--r--src/bin/pg_controldata/t/001_pg_controldata.pl21
2 files changed, 38 insertions, 9 deletions
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index cc73b7d6c29..f9dc854b4a9 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -95,7 +95,6 @@ main(int argc, char *argv[])
char mock_auth_nonce_str[MOCK_AUTH_NONCE_LEN * 2 + 1];
const char *strftime_fmt = "%c";
const char *progname;
- XLogSegNo segno;
char xlogfilename[MAXFNAMELEN];
int c;
int i;
@@ -169,10 +168,11 @@ main(int argc, char *argv[])
WalSegSz = ControlFile->xlog_seg_size;
if (!IsValidWalSegSize(WalSegSz))
- fprintf(stderr,
- _("WARNING: WAL segment size specified, %d bytes, is not a power of two between 1MB and 1GB.\n"
- "The file is corrupt and the results below are untrustworthy.\n"),
- WalSegSz);
+ printf(_("WARNING: invalid WAL segment size\n"
+ "The WAL segment size stored in the file, %d bytes, is not a power of two\n"
+ "between 1 MB and 1 GB. The file is corrupt and the results below are\n"
+ "untrustworthy.\n\n"),
+ WalSegSz);
/*
* This slightly-chintzy coding will work as long as the control file
@@ -193,10 +193,20 @@ main(int argc, char *argv[])
/*
* Calculate name of the WAL file containing the latest checkpoint's REDO
* start point.
+ *
+ * A corrupted control file could report a WAL segment size of 0, and to
+ * guard against division by zero, we need to treat that specially.
*/
- XLByteToSeg(ControlFile->checkPointCopy.redo, segno, WalSegSz);
- XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
- segno, WalSegSz);
+ if (WalSegSz != 0)
+ {
+ XLogSegNo segno;
+
+ XLByteToSeg(ControlFile->checkPointCopy.redo, segno, WalSegSz);
+ XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
+ segno, WalSegSz);
+ }
+ else
+ strcpy(xlogfilename, _("???"));
/*
* Format system_identifier and mock_authentication_nonce separately to
diff --git a/src/bin/pg_controldata/t/001_pg_controldata.pl b/src/bin/pg_controldata/t/001_pg_controldata.pl
index 40405516cad..af9fad7a38b 100644
--- a/src/bin/pg_controldata/t/001_pg_controldata.pl
+++ b/src/bin/pg_controldata/t/001_pg_controldata.pl
@@ -2,7 +2,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
-use Test::More tests => 13;
+use Test::More tests => 17;
program_help_ok('pg_controldata');
program_version_ok('pg_controldata');
@@ -16,3 +16,22 @@ $node->init;
command_like([ 'pg_controldata', $node->data_dir ],
qr/checkpoint/, 'pg_controldata produces output');
+
+
+# check with a corrupted pg_control
+
+my $pg_control = $node->data_dir . '/global/pg_control';
+my $size = (stat($pg_control))[7];
+
+open my $fh, '>', $pg_control or BAIL_OUT($!);
+binmode $fh;
+# fill file with zeros
+print $fh pack("x[$size]");
+close $fh;
+
+command_checks_all([ 'pg_controldata', $node->data_dir ],
+ 0,
+ [ qr/WARNING: Calculated CRC checksum does not match value stored in file/,
+ qr/WARNING: invalid WAL segment size/ ],
+ [ qr/^$/ ],
+ 'pg_controldata with corrupted pg_control');