While checking return/error handling of file system calls, I found that the copy_file_range() call in pg_combinebackup has a potential problem. If copy_file_range() returns 0, which is a documented condition, then the loop never makes progress and could spin forever.

The other uses of copy_file_range() in the tree are surrounded by different logic and don't appear to have this problem.

My suggested fix is to make a return value of 0 an error. It most likely indicates that the source file has an unexpected size.
From 83b7fadd149271e4a52843d134c60b97ee5bac7a Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Mon, 22 Jun 2026 09:15:28 +0200
Subject: [PATCH] Fix handling of copy_file_range() return value

Treat copy_file_range() return value of zero as an error: it indicates
that no bytes could be copied (perhaps the source file is shorter than
expected), and the existing retry loop would otherwise spin forever
since nwritten would never reach BLCKSZ.

The other uses of copy_file_range() in the tree don't have this
problem.
---
 src/bin/pg_combinebackup/reconstruct.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/bin/pg_combinebackup/reconstruct.c 
b/src/bin/pg_combinebackup/reconstruct.c
index 3349aa2441d..38e756be7ef 100644
--- a/src/bin/pg_combinebackup/reconstruct.c
+++ b/src/bin/pg_combinebackup/reconstruct.c
@@ -705,6 +705,9 @@ write_reconstructed_file(char *input_filename,
                                if (wb < 0)
                                        pg_fatal("error while copying file 
range from \"%s\" to \"%s\": %m",
                                                         input_filename, 
output_filename);
+                               else if (wb == 0)
+                                       pg_fatal("unexpected end of file while 
copying file range from \"%s\" to \"%s\"",
+                                                        input_filename, 
output_filename);
 
                                nwritten += wb;
 
-- 
2.54.0

Reply via email to