From aecefc5b1a99767cecf00d3cabf53917d395cdc6 Mon Sep 17 00:00:00 2001 From: Jan Nidzwetzki Date: Fri, 16 Oct 2026 14:24:05 +0200 Subject: [PATCH v3 3/4] Use pg_parse_lsn() for timeline history switchpoints readTimeLineHistory() parsed the switchpoint on each history file line with sscanf("%X/%08X"). Commit f31d6fbc31d converted the frontend copy of this code in pg_rewind, but not the backend one. Convert it in the same way. As in pg_rewind, characters directly after the switchpoint are now rejected rather than ignored. Add a TAP test covering overlong components and trailing characters. --- src/backend/access/transam/timeline.c | 37 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c index d80c8ffe0a7..cc27587a07c 100644 --- a/src/backend/access/transam/timeline.c +++ b/src/backend/access/transam/timeline.c @@ -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 */ -- 2.52.0