From 2ccd1267a37cec3a7b92d5edf92cadfa9aef897d Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Mon, 10 Nov 2025 09:37:37 -0800 Subject: [PATCH 1/4] [libc] fwrite_unlocked: only return errno if an actual error occurred. fwrite and friends don't modify errno if no error occurred. Therefore frite_unlocked's return value shouldn't be constructed from errno without checking if an error actually occurred. --- libc/src/stdio/printf_core/vfprintf_internal.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index 564441d3bf51a..a14ddee5f62fd 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -51,8 +51,14 @@ LIBC_INLINE void funlockfile(::FILE *f) { ::funlockfile(f); } LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, ::FILE *f) { // Need to use system errno in this case, as system write will set this errno - // which we need to propagate back into our code. - return {::fwrite_unlocked(ptr, size, nmemb, f), errno}; + // which we need to propagate back into our code. fwrite only modifies errno + // if there was an error, and errno may have previously been nonzero. Only + // return errno if there was an error. + auto bytes = ::fwrite_unlocked(ptr, size, nmemb, f); + if (bytes == nmemb * size) + return bytes; + else + return errno; } #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace internal From ccb1b257cfde77abea9a81d9e1acbc3126ca6a95 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Mon, 10 Nov 2025 10:21:33 -0800 Subject: [PATCH 2/4] FileIOResult is not a std::expected or similar. Don't treat it that way. --- libc/src/stdio/printf_core/vfprintf_internal.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index a14ddee5f62fd..ac7c167217b7f 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -55,10 +55,7 @@ LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size, // if there was an error, and errno may have previously been nonzero. Only // return errno if there was an error. auto bytes = ::fwrite_unlocked(ptr, size, nmemb, f); - if (bytes == nmemb * size) - return bytes; - else - return errno; + return {bytes, bytes == nmemb * size ? 0 : errno}; } #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace internal From 9b0318af4f9a0f4ed69a020322261a5523c60d1d Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Mon, 10 Nov 2025 11:10:35 -0800 Subject: [PATCH 3/4] Fix size calculation. --- libc/src/stdio/printf_core/vfprintf_internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index ac7c167217b7f..a1bea066f639a 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -54,8 +54,8 @@ LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size, // which we need to propagate back into our code. fwrite only modifies errno // if there was an error, and errno may have previously been nonzero. Only // return errno if there was an error. - auto bytes = ::fwrite_unlocked(ptr, size, nmemb, f); - return {bytes, bytes == nmemb * size ? 0 : errno}; + size_t bytes = ::fwrite_unlocked(ptr, size, nmemb, f); + return {bytes, bytes == size ? 0 : errno}; } #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace internal From 64fad094b2cf1f30002f01b196f379a251408f96 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Mon, 10 Nov 2025 12:02:50 -0800 Subject: [PATCH 4/4] Fix calculation to be against nmemb, not size. --- libc/src/stdio/printf_core/vfprintf_internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index a1bea066f639a..c47a03d741f98 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -54,8 +54,8 @@ LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size, // which we need to propagate back into our code. fwrite only modifies errno // if there was an error, and errno may have previously been nonzero. Only // return errno if there was an error. - size_t bytes = ::fwrite_unlocked(ptr, size, nmemb, f); - return {bytes, bytes == size ? 0 : errno}; + size_t members_written = ::fwrite_unlocked(ptr, size, nmemb, f); + return {members_written, members_written == nmemb ? 0 : errno}; } #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace internal