From e9d20989b522bc61f7419e734d49aa442d170403 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Mon, 6 Jul 2026 20:01:20 +0530 Subject: [PATCH v2] pg_rewind: Error out on unexpectedly vanished files during traversal recurse_dir() accepted an ENOENT from lstat() with an empty branch and then fell through to inspect fst.st_mode, reading an uninitialized struct stat. The original comment justified skipping on the grounds that "the new primary is running and the file was just removed", but that reasoning does not apply here: recurse_dir() only ever scans a stopped source data directory (in local mode) or the target data directory. The running-source case uses libpq_traverse_files() and never reaches this code. Since no file is expected to vanish mid-scan in either directory, treat a failed lstat() as a hard error in all cases. This also removes the uninitialized read and the stale TODO about differentiating the target directory. Discussion: https://postgr.es/m/CAJTYsWVoJ7-TdjGw3jQ40%2Ba7cBYjr2GZLEC_tyE22ZKqQnDrWQ%40mail.gmail.com --- src/bin/pg_rewind/file_ops.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c index acd8fa758fd..31e828f779f 100644 --- a/src/bin/pg_rewind/file_ops.c +++ b/src/bin/pg_rewind/file_ops.c @@ -423,23 +423,16 @@ recurse_dir(const char *datadir, const char *parentpath, snprintf(fullpath, sizeof(fullpath), "%s/%s", fullparentpath, xlde->d_name); + /* + * We don't expect any file to vanish mid-scan: recurse_dir() runs + * only over a stopped source data directory (in local mode) or the + * target data directory, never over a running server (the + * source-server case goes through libpq_traverse_files() instead). + * So treat a failed lstat() as a hard error in all cases. + */ if (lstat(fullpath, &fst) < 0) - { - if (errno == ENOENT) - { - /* - * File doesn't exist anymore. This is ok, if the new primary - * is running and the file was just removed. If it was a data - * file, there should be a WAL record of the removal. If it - * was something else, it couldn't have been anyway. - * - * TODO: But complain if we're processing the target dir! - */ - } - else - pg_fatal("could not stat file \"%s\": %m", - fullpath); - } + pg_fatal("could not stat file \"%s\": %m", + fullpath); if (parentpath) snprintf(path, sizeof(path), "%s/%s", parentpath, xlde->d_name); -- 2.34.1