1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Use pg_parse_lsn() for timeline history switchpoints

readTimeLineHistory() previously parsed WAL switchpoints in timeline
history files using sscanf("%X/%08X") into uint32 values. An
overlong high component could overflow, while an overlong low component
was truncated to its first eight digits. Trailing characters were also
ignored.

Extract the switchpoint token and use pg_parse_lsn() to validate and
convert it, requiring one to eight hexadecimal digits per component
with no trailing characters, as for pg_lsn input. This matches the
change to pg_rewind's history file parser in commit f31d6fbc31.

Author: Jan Nidzwetzki <jan@planetscale.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/8b1abbd0-7335-4e68-93ec-91cdbbfd9568@planetscale.com
This commit is contained in:
Fujii Masao
2026-10-22 17:35:28 +09:00
parent ae75d12b50
commit 5ffb8c7409

View File

@@ -39,6 +39,7 @@
#include "access/xlog_internal.h"
#include "access/xlogarchive.h"
#include "access/xlogdefs.h"
#include "common/pg_parse_lsn.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "utils/wait_event.h"
@@ -128,10 +129,13 @@ readTimeLineHistory(TimeLineID targetTLI)
char fline[MAXPGPATH];
char *res;
char *ptr;
char *token_end;
char save;
TimeLineID tli;
uint32 switchpoint_hi;
uint32 switchpoint_lo;
int nfields;
XLogRecPtr switchpoint;
bool valid_switchpoint = false;
int nchars;
size_t nspaces;
pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_READ);
res = fgets(fline, sizeof(fline), fd);
@@ -155,16 +159,33 @@ readTimeLineHistory(TimeLineID targetTLI)
if (*ptr == '\0' || *ptr == '#')
continue;
nfields = sscanf(fline, "%u\t%X/%08X", &tli, &switchpoint_hi, &switchpoint_lo);
if (nfields < 1)
if (sscanf(fline, "%u%n", &tli, &nchars) != 1)
{
/* expect a numeric timeline ID as first field of line */
ereport(FATAL,
(errmsg("syntax error in history file: %s", fline),
errhint("Expected a numeric timeline ID.")));
}
if (nfields != 3)
/* the switchpoint location follows, separated by whitespace */
ptr = fline + nchars;
nspaces = strspn(ptr, " \t\n\r\f\v");
if (nspaces > 0)
{
ptr += nspaces;
/*
* isolate the location from the rest of the line before parsing
* it
*/
token_end = ptr + strcspn(ptr, " \t\n\r\f\v");
save = *token_end;
*token_end = '\0';
valid_switchpoint = pg_parse_lsn(ptr, &switchpoint);
*token_end = save;
}
if (!valid_switchpoint)
ereport(FATAL,
(errmsg("syntax error in history file: %s", fline),
errhint("Expected a write-ahead log switchpoint location.")));
@@ -179,7 +200,7 @@ readTimeLineHistory(TimeLineID targetTLI)
entry = palloc_object(TimeLineHistoryEntry);
entry->tli = tli;
entry->begin = prevend;
entry->end = ((uint64) (switchpoint_hi)) << 32 | (uint64) switchpoint_lo;
entry->end = switchpoint;
prevend = entry->end;
/* Build list with newest item first */