From f90d1b6846d87e0f54ba767328a4814fd3abd3c0 Mon Sep 17 00:00:00 2001 From: AZero13 Date: Thu, 11 Dec 2025 16:18:52 -0500 Subject: [PATCH] [3.13] gh-142571: Check for errors before calling each syscall in `PyUnstable_CopyPerfMapFile()` (GH-142460) (cherry picked from commit 9fe6e3ed365f40d89a47c2a255e11f0363e9aa78) Co-authored-by: AZero13 Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> Co-authored-by: Victor Stinner Co-authored-by: Pablo Galindo Salgado --- ...-12-11-09-06-36.gh-issue-142571.Csdxnn.rst | 1 + Python/sysmodule.c | 23 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2025-12-11-09-06-36.gh-issue-142571.Csdxnn.rst diff --git a/Misc/NEWS.d/next/C API/2025-12-11-09-06-36.gh-issue-142571.Csdxnn.rst b/Misc/NEWS.d/next/C API/2025-12-11-09-06-36.gh-issue-142571.Csdxnn.rst new file mode 100644 index 00000000000000..ea419b4fe1d6b0 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2025-12-11-09-06-36.gh-issue-142571.Csdxnn.rst @@ -0,0 +1 @@ +:c:func:`!PyUnstable_CopyPerfMapFile` now checks that opening the file succeeded before flushing. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 993763fcbe6a71..8d47177340d780 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2609,20 +2609,31 @@ PyAPI_FUNC(int) PyUnstable_CopyPerfMapFile(const char* parent_filename) { } char buf[4096]; PyThread_acquire_lock(perf_map_state.map_lock, 1); - int fflush_result = 0, result = 0; + int result = 0; while (1) { size_t bytes_read = fread(buf, 1, sizeof(buf), from); + if (bytes_read == 0) { + if (ferror(from)) { + result = -1; + } + break; + } + size_t bytes_written = fwrite(buf, 1, bytes_read, perf_map_state.perf_map); - fflush_result = fflush(perf_map_state.perf_map); - if (fflush_result != 0 || bytes_read == 0 || bytes_written < bytes_read) { + if (bytes_written < bytes_read) { result = -1; - goto close_and_release; + break; } + + if (fflush(perf_map_state.perf_map) != 0) { + result = -1; + break; + } + if (bytes_read < sizeof(buf) && feof(from)) { - goto close_and_release; + break; } } -close_and_release: fclose(from); PyThread_release_lock(perf_map_state.map_lock); return result;