[BUG] pg_rewind: file sync bypass and findLastCheckpoint boundary crash

Started by Srinath Reddy Sadipirallaabout 6 hours ago2 messageshackers
Beta feature

Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.

appliessuccessCI history

You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:

docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253605
psql -h localhost -U postgres

Built from patchset v1 (message #1), August 30, 2026 at 04:57 AM.

Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:

git clone --branch t253605_1 https://github.com/hackorum-dev/postgres.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t253605_1 && git checkout t253605_1

Patchset v1 (message #1) is on t253605_1

Jump to latest
#1Srinath Reddy Sadipiralla
srinath2133@gmail.com

Hi,

While working on [0], I have found a bug in pg_rewind where it
bypasses the file sync phase if the target cluster's WAL ends
exactly at the divergence point. Fixing this logic exposed another
crash bug in findLastCheckpoint().

Bug 1: The File Sync Bypass
If you cleanly shut down a primary and promote a standby, the
target's WAL ends exactly where the new timeline branches.
In pg_rewind.c, the timeline divergence logic contains this check:

if (target_wal_endrec > divergerec) {
rewind_needed = true;
} else {
Assert(target_wal_endrec == divergerec);
rewind_needed = false;
}

If rewind_needed is false, pg_rewind exits immediately. While it's
true there are no modified data blocks to rewind, exiting here
bypasses the file sync phase. The target cluster is left without the
source's new timeline history file, any non-WAL-logged file modifications
(like postgresql.auto.conf), and pg_rewind fails to update the target's
pg_control file with the new timeline and DB_IN_ARCHIVE_RECOVERY state.

Bug 2: The findLastCheckpoint Crash
If we fix Bug 1 by simply removing the rewind_needed = false
so the file sync can run, pg_rewind crashes immediately with
error: could not find previous WAL record at <LSN>: invalid record length
at <LSN>: expected at least 24, got 0

This happens because findLastCheckpoint attempts to read
backward starting at divergerec. But because the target shut
down cleanly, divergerec points exactly to the end of the written WAL.
The reader hits unwritten zeroes, expects a 24-byte record header, and
throws a fatal error. The original early exit was masking this hide in the
backward scanner.

The attached patch has a reproducer with as a TAP test and
resolves both issues, thoughts?

--
Thanks :)
Srinath Reddy Sadipiralla
EDB: https://www.enterprisedb.com/
"i have no special talent i am only passionately curious - Albert Einstein"

Attachments:

t253605_1
v1-0001-Fix-pg_rewind-file-sync-bypass-and-findLastCheckpoin.patchapplication/octet-stream; name=v1-0001-Fix-pg_rewind-file-sync-bypass-and-findLastCheckpoin.patchDownload+207-64
#2Srinath Reddy Sadipiralla
srinath2133@gmail.com
In reply to: Srinath Reddy Sadipiralla (#1)
Re: [BUG] pg_rewind: file sync bypass and findLastCheckpoint boundary crash

On Sun, Aug 30, 2026 at 10:15 AM Srinath Reddy Sadipiralla <
srinath2133@gmail.com> wrote:

Hi,

While working on [0], I have found a bug in pg_rewind where it

sorry forgot to add [0]/messages/by-id/CAFC+b6pztjF8AiM=GOs=SeNOYLpZnUSSMJsRKKZdf-MKJj22VQ@mail.gmail.com link.

[0]: /messages/by-id/CAFC+b6pztjF8AiM=GOs=SeNOYLpZnUSSMJsRKKZdf-MKJj22VQ@mail.gmail.com
/messages/by-id/CAFC+b6pztjF8AiM=GOs=SeNOYLpZnUSSMJsRKKZdf-MKJj22VQ@mail.gmail.com

--
Thanks :)
Srinath Reddy Sadipiralla
EDB: https://www.enterprisedb.com/