From 25c7d79a96f2ee0db4c49ee4854c3ae986394dda Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Tue, 7 Oct 2025 06:16:51 +0000 Subject: [PATCH 01/25] Change writer to store chars written as size_t --- libc/src/stdio/printf_core/printf_main.h | 3 ++- libc/src/stdio/printf_core/write_int_converter.h | 4 ++-- libc/src/stdio/printf_core/writer.h | 8 ++++---- libc/src/stdlib/strfromd.cpp | 3 ++- libc/src/stdlib/strfromf.cpp | 3 ++- libc/src/stdlib/strfroml.cpp | 3 ++- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/libc/src/stdio/printf_core/printf_main.h b/libc/src/stdio/printf_core/printf_main.h index 57f29858d5298..c654571d1dffd 100644 --- a/libc/src/stdio/printf_core/printf_main.h +++ b/libc/src/stdio/printf_core/printf_main.h @@ -38,7 +38,8 @@ int printf_main(Writer *writer, const char *__restrict str, return result; } - return writer->get_chars_written(); + // TODO overflow + return static_cast(writer->get_chars_written()); } } // namespace printf_core diff --git a/libc/src/stdio/printf_core/write_int_converter.h b/libc/src/stdio/printf_core/write_int_converter.h index efcff278bd284..04b2bef05bc7b 100644 --- a/libc/src/stdio/printf_core/write_int_converter.h +++ b/libc/src/stdio/printf_core/write_int_converter.h @@ -29,11 +29,11 @@ LIBC_INLINE int convert_write_int(Writer *writer, return NULLPTR_WRITE_ERROR; #endif // LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS - int written = writer->get_chars_written(); + size_t written = writer->get_chars_written(); switch (to_conv.length_modifier) { case LengthModifier::none: - *reinterpret_cast(to_conv.conv_val_ptr) = written; + *reinterpret_cast(to_conv.conv_val_ptr) = static_cast(written); break; case LengthModifier::l: *reinterpret_cast(to_conv.conv_val_ptr) = written; diff --git a/libc/src/stdio/printf_core/writer.h b/libc/src/stdio/printf_core/writer.h index 1d4734a51b9b8..9de108ece510f 100644 --- a/libc/src/stdio/printf_core/writer.h +++ b/libc/src/stdio/printf_core/writer.h @@ -127,7 +127,7 @@ template struct WriteBuffer { template class Writer final { WriteBuffer &wb; - int chars_written = 0; + size_t chars_written = 0; LIBC_INLINE int pad(char new_char, size_t length) { // First, fill as much of the buffer as possible with the padding char. @@ -161,7 +161,7 @@ template class Writer final { // Takes a string, copies it into the buffer if there is space, else passes it // to the overflow mechanism to be handled separately. LIBC_INLINE int write(cpp::string_view new_string) { - chars_written += static_cast(new_string.size()); + chars_written += new_string.size(); if (LIBC_LIKELY(wb.buff_cur + new_string.size() <= wb.buff_len)) { inline_memcpy(wb.buff + wb.buff_cur, new_string.data(), new_string.size()); @@ -175,7 +175,7 @@ template class Writer final { // if there is space, else calls pad which will loop and call the overflow // mechanism on a secondary buffer. LIBC_INLINE int write(char new_char, size_t length) { - chars_written += static_cast(length); + chars_written += length; if (LIBC_LIKELY(wb.buff_cur + length <= wb.buff_len)) { inline_memset(wb.buff + wb.buff_cur, static_cast(new_char), @@ -199,7 +199,7 @@ template class Writer final { return wb.overflow_write(char_string_view); } - LIBC_INLINE int get_chars_written() { return chars_written; } + LIBC_INLINE size_t get_chars_written() { return chars_written; } }; // Class-template auto deduction helpers. diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp index f51e6d4c7f1df..c0989f1a97dca 100644 --- a/libc/src/stdlib/strfromd.cpp +++ b/libc/src/stdlib/strfromd.cpp @@ -36,7 +36,8 @@ LLVM_LIBC_FUNCTION(int, strfromd, if (n > 0) wb.buff[wb.buff_cur] = '\0'; - return writer.get_chars_written(); + // TODO overflow + return static_cast(writer.get_chars_written()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdlib/strfromf.cpp b/libc/src/stdlib/strfromf.cpp index 14dbfdb25bab6..01090c997af1b 100644 --- a/libc/src/stdlib/strfromf.cpp +++ b/libc/src/stdlib/strfromf.cpp @@ -36,7 +36,8 @@ LLVM_LIBC_FUNCTION(int, strfromf, if (n > 0) wb.buff[wb.buff_cur] = '\0'; - return writer.get_chars_written(); + // TODO overflow + return static_cast(writer.get_chars_written()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdlib/strfroml.cpp b/libc/src/stdlib/strfroml.cpp index 12f22a8a2fb65..436243d1e1c38 100644 --- a/libc/src/stdlib/strfroml.cpp +++ b/libc/src/stdlib/strfroml.cpp @@ -41,7 +41,8 @@ LLVM_LIBC_FUNCTION(int, strfroml, if (n > 0) wb.buff[wb.buff_cur] = '\0'; - return writer.get_chars_written(); + // TODO overflow + return static_cast(writer.get_chars_written()); } } // namespace LIBC_NAMESPACE_DECL From 362c00e1c89faafbff7605233bb752447491a7be Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Tue, 7 Oct 2025 06:34:43 +0000 Subject: [PATCH 02/25] Prinf internals: use -errno as return values rather than custrom error values --- libc/src/stdio/printf_core/core_structs.h | 12 ++++++------ libc/src/stdio/printf_core/fixed_converter.h | 3 ++- libc/src/stdio/printf_core/int_converter.h | 3 ++- libc/src/stdio/printf_core/vasprintf_internal.h | 5 +++-- libc/src/stdio/printf_core/vfprintf_internal.h | 3 ++- libc/src/stdio/printf_core/write_int_converter.h | 3 ++- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index e27f77b6b594a..83e251a3b1da5 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -134,12 +134,12 @@ template LIBC_INLINE constexpr TypeDesc type_desc_from_type() { constexpr int WRITE_OK = 0; // These are the printf return values for when an error has occurred. They are // all negative, and should be distinct. -constexpr int FILE_WRITE_ERROR = -1; -constexpr int FILE_STATUS_ERROR = -2; -constexpr int NULLPTR_WRITE_ERROR = -3; -constexpr int INT_CONVERSION_ERROR = -4; -constexpr int FIXED_POINT_CONVERSION_ERROR = -5; -constexpr int ALLOCATION_ERROR = -6; +// constexpr int FILE_WRITE_ERROR = -1; +// constexpr int FILE_STATUS_ERROR = -2; +// constexpr int NULLPTR_WRITE_ERROR = -3; +// constexpr int INT_CONVERSION_ERROR = -4; +// constexpr int FIXED_POINT_CONVERSION_ERROR = -5; +// constexpr int ALLOCATION_ERROR = -6; } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/fixed_converter.h b/libc/src/stdio/printf_core/fixed_converter.h index e8a3314967562..a7185dcb11d8a 100644 --- a/libc/src/stdio/printf_core/fixed_converter.h +++ b/libc/src/stdio/printf_core/fixed_converter.h @@ -20,6 +20,7 @@ #include "src/stdio/printf_core/converter_utils.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/writer.h" +#include "hdr/errno_macros.h" #include #include @@ -59,7 +60,7 @@ LIBC_INLINE constexpr uint32_t const_ten_exp(uint32_t exponent) { READ_FX_BITS(unsigned LENGTH_MODIFIER accum); \ } else { \ LIBC_ASSERT(false && "Invalid conversion name passed to convert_fixed"); \ - return FIXED_POINT_CONVERSION_ERROR; \ + return -EINVAL; \ } \ } while (false) diff --git a/libc/src/stdio/printf_core/int_converter.h b/libc/src/stdio/printf_core/int_converter.h index 11234c32ce997..08e27e1a60447 100644 --- a/libc/src/stdio/printf_core/int_converter.h +++ b/libc/src/stdio/printf_core/int_converter.h @@ -17,6 +17,7 @@ #include "src/stdio/printf_core/converter_utils.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/writer.h" +#include "hdr/errno_macros.h" #include #include @@ -91,7 +92,7 @@ LIBC_INLINE int convert_int(Writer *writer, cpp::array buf; auto str = details::num_to_strview(num, buf, to_conv.conv_name); if (!str) - return INT_CONVERSION_ERROR; + return -ERANGE; size_t digits_written = str->size(); diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h index 283d8df2810fb..4e868edca1a1e 100644 --- a/libc/src/stdio/printf_core/vasprintf_internal.h +++ b/libc/src/stdio/printf_core/vasprintf_internal.h @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "hdr/errno_macros.h" #include "hdr/func/free.h" #include "hdr/func/malloc.h" #include "hdr/func/realloc.h" @@ -29,7 +30,7 @@ LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) { if (new_buff == nullptr) { if (wb->buff != wb->init_buff) free(wb->buff); - return printf_core::ALLOCATION_ERROR; + return -ENOMEM; } if (isBuffOnStack) inline_memcpy(new_buff, wb->buff, wb->buff_cur); @@ -57,7 +58,7 @@ LIBC_INLINE int vasprintf_internal(char **ret, const char *__restrict format, if (wb.buff == init_buff_on_stack) { *ret = static_cast(malloc(ret_val + 1)); if (ret == nullptr) - return printf_core::ALLOCATION_ERROR; + return -ENOMEM; inline_memcpy(*ret, wb.buff, ret_val); } else { *ret = wb.buff; diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index 630de9d9d43dd..552f2a2f5e34d 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_VFPRINTF_INTERNAL_H #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_VFPRINTF_INTERNAL_H +#include "hdr/errno_macros.h" #include "src/__support/File/file.h" #include "src/__support/arg_list.h" #include "src/__support/macros/attributes.h" // For LIBC_INLINE @@ -63,7 +64,7 @@ LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) { size_t written = internal::fwrite_unlocked(new_str.data(), sizeof(char), new_str.size(), target_file); if (written != new_str.size() || internal::ferror_unlocked(target_file)) - return FILE_WRITE_ERROR; + return -EIO; return WRITE_OK; } diff --git a/libc/src/stdio/printf_core/write_int_converter.h b/libc/src/stdio/printf_core/write_int_converter.h index 04b2bef05bc7b..15c32d9ac272a 100644 --- a/libc/src/stdio/printf_core/write_int_converter.h +++ b/libc/src/stdio/printf_core/write_int_converter.h @@ -12,6 +12,7 @@ #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/writer.h" +#include "hdr/errno_macros.h" #include #include @@ -26,7 +27,7 @@ LIBC_INLINE int convert_write_int(Writer *writer, #ifndef LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS // This is an additional check added by LLVM-libc. if (to_conv.conv_val_ptr == nullptr) - return NULLPTR_WRITE_ERROR; + return -EINVAL; #endif // LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS size_t written = writer->get_chars_written(); From f8c75692e43cbb7de691188a8b52f9392b096cf0 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Tue, 7 Oct 2025 07:07:25 +0000 Subject: [PATCH 03/25] Refactor printf family functions to use PrintfResult --- libc/src/stdio/asprintf.cpp | 13 +++++++++++-- libc/src/stdio/generic/fprintf.cpp | 13 +++++++++++-- libc/src/stdio/generic/printf.cpp | 13 +++++++++++-- libc/src/stdio/generic/vfprintf.cpp | 13 +++++++++++-- libc/src/stdio/generic/vprintf.cpp | 13 +++++++++++-- libc/src/stdio/printf_core/core_structs.h | 12 ++++++++++++ libc/src/stdio/printf_core/printf_main.h | 9 ++++----- libc/src/stdio/printf_core/vasprintf_internal.h | 12 ++++++------ libc/src/stdio/printf_core/vfprintf_internal.h | 6 +++--- libc/src/stdio/snprintf.cpp | 14 ++++++++++++-- libc/src/stdio/sprintf.cpp | 14 ++++++++++++-- libc/src/stdio/vasprintf.cpp | 11 ++++++++++- libc/src/stdio/vsnprintf.cpp | 14 ++++++++++++-- libc/src/stdio/vsprintf.cpp | 13 +++++++++++-- 14 files changed, 137 insertions(+), 33 deletions(-) diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp index f8cfb74ce48ea..d392c658b898c 100644 --- a/libc/src/stdio/asprintf.cpp +++ b/libc/src/stdio/asprintf.cpp @@ -22,8 +22,17 @@ LLVM_LIBC_FUNCTION(int, asprintf, // and pointer semantics, as well as handling // destruction automatically. va_end(vlist); - int ret = printf_core::vasprintf_internal(buffer, format, args); - return ret; + auto ret_val = printf_core::vasprintf_internal(buffer, format, args); + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/fprintf.cpp b/libc/src/stdio/generic/fprintf.cpp index 087aeadfc52c5..64d6694770e4e 100644 --- a/libc/src/stdio/generic/fprintf.cpp +++ b/libc/src/stdio/generic/fprintf.cpp @@ -27,8 +27,17 @@ LLVM_LIBC_FUNCTION(int, fprintf, // and pointer semantics, as well as handling // destruction automatically. va_end(vlist); - int ret_val = printf_core::vfprintf_internal(stream, format, args); - return ret_val; + auto ret_val = printf_core::vfprintf_internal(stream, format, args); + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/printf.cpp b/libc/src/stdio/generic/printf.cpp index bb7c7c86f843f..0020cce2359e8 100644 --- a/libc/src/stdio/generic/printf.cpp +++ b/libc/src/stdio/generic/printf.cpp @@ -31,9 +31,18 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { // and pointer semantics, as well as handling // destruction automatically. va_end(vlist); - int ret_val = printf_core::vfprintf_internal( + auto ret_val = printf_core::vfprintf_internal( reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args); - return ret_val; + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/vfprintf.cpp b/libc/src/stdio/generic/vfprintf.cpp index 01f4265f118a6..6311318862bd6 100644 --- a/libc/src/stdio/generic/vfprintf.cpp +++ b/libc/src/stdio/generic/vfprintf.cpp @@ -24,8 +24,17 @@ LLVM_LIBC_FUNCTION(int, vfprintf, internal::ArgList args(vlist); // This holder class allows for easier copying // and pointer semantics, as well as handling // destruction automatically. - int ret_val = printf_core::vfprintf_internal(stream, format, args); - return ret_val; + auto ret_val = printf_core::vfprintf_internal(stream, format, args); + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/vprintf.cpp b/libc/src/stdio/generic/vprintf.cpp index 08d71515646ed..73b9701ee2eda 100644 --- a/libc/src/stdio/generic/vprintf.cpp +++ b/libc/src/stdio/generic/vprintf.cpp @@ -29,9 +29,18 @@ LLVM_LIBC_FUNCTION(int, vprintf, internal::ArgList args(vlist); // This holder class allows for easier copying // and pointer semantics, as well as handling // destruction automatically. - int ret_val = printf_core::vfprintf_internal( + auto ret_val = printf_core::vfprintf_internal( reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args); - return ret_val; + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index 83e251a3b1da5..e397e4a5b3abe 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -22,6 +22,18 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { +struct PrintfResult { + size_t value; + int error; + + constexpr PrintfResult(size_t val) : value(val), error(0) {} + constexpr PrintfResult(size_t val, int error) : value(val), error(error) {} + + constexpr bool has_error() { return error != 0; } + + constexpr operator size_t() { return value; } +}; + // These length modifiers match the length modifiers in the format string, which // is why they are formatted differently from the rest of the file. enum class LengthModifier { hh, h, l, ll, j, z, t, L, w, wf, none }; diff --git a/libc/src/stdio/printf_core/printf_main.h b/libc/src/stdio/printf_core/printf_main.h index c654571d1dffd..6a9c9a00265d1 100644 --- a/libc/src/stdio/printf_core/printf_main.h +++ b/libc/src/stdio/printf_core/printf_main.h @@ -22,7 +22,7 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { template -int printf_main(Writer *writer, const char *__restrict str, +PrintfResult printf_main(Writer *writer, const char *__restrict str, internal::ArgList &args) { Parser parser(str, args); int result = 0; @@ -35,11 +35,10 @@ int printf_main(Writer *writer, const char *__restrict str, result = writer->write(cur_section.raw_string); if (result < 0) - return result; + return {0, -result}; } - - // TODO overflow - return static_cast(writer->get_chars_written()); + + return writer->get_chars_written(); } } // namespace printf_core diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h index 4e868edca1a1e..bfc02fedf5244 100644 --- a/libc/src/stdio/printf_core/vasprintf_internal.h +++ b/libc/src/stdio/printf_core/vasprintf_internal.h @@ -43,7 +43,7 @@ LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) { constexpr size_t DEFAULT_BUFFER_SIZE = 200; -LIBC_INLINE int vasprintf_internal(char **ret, const char *__restrict format, +LIBC_INLINE PrintfResult vasprintf_internal(char **ret, const char *__restrict format, internal::ArgList args) { char init_buff_on_stack[DEFAULT_BUFFER_SIZE]; printf_core::WriteBuffer::value> wb( @@ -51,19 +51,19 @@ LIBC_INLINE int vasprintf_internal(char **ret, const char *__restrict format, printf_core::Writer writer(wb); auto ret_val = printf_core::printf_main(&writer, format, args); - if (ret_val < 0) { + if (ret_val.has_error()) { *ret = nullptr; - return -1; + return ret_val; } if (wb.buff == init_buff_on_stack) { - *ret = static_cast(malloc(ret_val + 1)); + *ret = static_cast(malloc(ret_val.value + 1)); if (ret == nullptr) return -ENOMEM; - inline_memcpy(*ret, wb.buff, ret_val); + inline_memcpy(*ret, wb.buff, ret_val.value); } else { *ret = wb.buff; } - (*ret)[ret_val] = '\0'; + (*ret)[ret_val.value] = '\0'; // TODO OK HERE or overflow return ret_val; } } // namespace printf_core diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index 552f2a2f5e34d..71a85077e92b8 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -68,7 +68,7 @@ LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) { return WRITE_OK; } -LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream, +LIBC_INLINE PrintfResult vfprintf_internal(::FILE *__restrict stream, const char *__restrict format, internal::ArgList &args) { constexpr size_t BUFF_SIZE = 1024; @@ -77,10 +77,10 @@ LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream, buffer, BUFF_SIZE, &file_write_hook, reinterpret_cast(stream)); Writer writer(wb); internal::flockfile(stream); - int retval = printf_main(&writer, format, args); + auto retval = printf_main(&writer, format, args); int flushval = wb.overflow_write(""); if (flushval != WRITE_OK) - retval = flushval; + retval.error = -flushval; internal::funlockfile(stream); return retval; } diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp index c8940862f711f..8c22935b849a0 100644 --- a/libc/src/stdio/snprintf.cpp +++ b/libc/src/stdio/snprintf.cpp @@ -32,10 +32,20 @@ LLVM_LIBC_FUNCTION(int, snprintf, wb(buffer, (buffsz > 0 ? buffsz - 1 : 0)); printf_core::Writer writer(wb); - int ret_val = printf_core::printf_main(&writer, format, args); + auto ret_val = printf_core::printf_main(&writer, format, args); + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. wb.buff[wb.buff_cur] = '\0'; - return ret_val; + + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp index 7be97d3591aaf..2557197894bec 100644 --- a/libc/src/stdio/sprintf.cpp +++ b/libc/src/stdio/sprintf.cpp @@ -33,9 +33,19 @@ LLVM_LIBC_FUNCTION(int, sprintf, wb(buffer, cpp::numeric_limits::max()); printf_core::Writer writer(wb); - int ret_val = printf_core::printf_main(&writer, format, args); + auto ret_val = printf_core::printf_main(&writer, format, args); + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } wb.buff[wb.buff_cur] = '\0'; - return ret_val; + + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vasprintf.cpp b/libc/src/stdio/vasprintf.cpp index 4a44d4a0f8842..d8ed3a36c7ecf 100644 --- a/libc/src/stdio/vasprintf.cpp +++ b/libc/src/stdio/vasprintf.cpp @@ -18,7 +18,16 @@ LLVM_LIBC_FUNCTION(int, vasprintf, internal::ArgList args(vlist); // This holder class allows for easier copying // and pointer semantics, as well as handling // destruction automatically. - return printf_core::vasprintf_internal(ret, format, args); + auto ret_val = printf_core::vasprintf_internal(ret, format, args); + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp index b07a2499a0dd3..f39051cdd4d75 100644 --- a/libc/src/stdio/vsnprintf.cpp +++ b/libc/src/stdio/vsnprintf.cpp @@ -29,10 +29,20 @@ LLVM_LIBC_FUNCTION(int, vsnprintf, wb(buffer, (buffsz > 0 ? buffsz - 1 : 0)); printf_core::Writer writer(wb); - int ret_val = printf_core::printf_main(&writer, format, args); + auto ret_val = printf_core::printf_main(&writer, format, args); + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. wb.buff[wb.buff_cur] = '\0'; - return ret_val; + + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp index 26d497be42125..4c4a3eefaa7b4 100644 --- a/libc/src/stdio/vsprintf.cpp +++ b/libc/src/stdio/vsprintf.cpp @@ -30,9 +30,18 @@ LLVM_LIBC_FUNCTION(int, vsprintf, wb(buffer, cpp::numeric_limits::max()); printf_core::Writer writer(wb); - int ret_val = printf_core::printf_main(&writer, format, args); + auto ret_val = printf_core::printf_main(&writer, format, args); + if (ret_val.has_error()) { + libc_errno = ret_val.error; + return -1; + } wb.buff[wb.buff_cur] = '\0'; - return ret_val; + + if (ret_val.value > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL From f8f35538b6dae5d99d58f46e1bc0b7c9055dc916 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Tue, 7 Oct 2025 07:07:45 +0000 Subject: [PATCH 04/25] Formatting --- libc/src/stdio/asprintf.cpp | 4 ++-- libc/src/stdio/generic/fprintf.cpp | 4 ++-- libc/src/stdio/generic/printf.cpp | 4 ++-- libc/src/stdio/generic/vfprintf.cpp | 4 ++-- libc/src/stdio/generic/vprintf.cpp | 4 ++-- libc/src/stdio/printf_core/printf_main.h | 4 ++-- libc/src/stdio/printf_core/vasprintf_internal.h | 5 +++-- libc/src/stdio/printf_core/vfprintf_internal.h | 4 ++-- libc/src/stdio/snprintf.cpp | 8 ++++---- libc/src/stdio/sprintf.cpp | 6 +++--- libc/src/stdio/vasprintf.cpp | 2 +- libc/src/stdio/vsnprintf.cpp | 8 ++++---- libc/src/stdio/vsprintf.cpp | 4 ++-- 13 files changed, 31 insertions(+), 30 deletions(-) diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp index d392c658b898c..13c1ee68ef0f2 100644 --- a/libc/src/stdio/asprintf.cpp +++ b/libc/src/stdio/asprintf.cpp @@ -30,9 +30,9 @@ LLVM_LIBC_FUNCTION(int, asprintf, if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } + } - return static_cast(ret_val.value); + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/fprintf.cpp b/libc/src/stdio/generic/fprintf.cpp index 64d6694770e4e..632264f944f44 100644 --- a/libc/src/stdio/generic/fprintf.cpp +++ b/libc/src/stdio/generic/fprintf.cpp @@ -35,9 +35,9 @@ LLVM_LIBC_FUNCTION(int, fprintf, if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } + } - return static_cast(ret_val.value); + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/printf.cpp b/libc/src/stdio/generic/printf.cpp index 0020cce2359e8..482a65cd5a2fa 100644 --- a/libc/src/stdio/generic/printf.cpp +++ b/libc/src/stdio/generic/printf.cpp @@ -40,9 +40,9 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } + } - return static_cast(ret_val.value); + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/vfprintf.cpp b/libc/src/stdio/generic/vfprintf.cpp index 6311318862bd6..6b39011123084 100644 --- a/libc/src/stdio/generic/vfprintf.cpp +++ b/libc/src/stdio/generic/vfprintf.cpp @@ -32,9 +32,9 @@ LLVM_LIBC_FUNCTION(int, vfprintf, if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } + } - return static_cast(ret_val.value); + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/vprintf.cpp b/libc/src/stdio/generic/vprintf.cpp index 73b9701ee2eda..09ba2ce0d32a9 100644 --- a/libc/src/stdio/generic/vprintf.cpp +++ b/libc/src/stdio/generic/vprintf.cpp @@ -38,9 +38,9 @@ LLVM_LIBC_FUNCTION(int, vprintf, if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } + } - return static_cast(ret_val.value); + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/printf_main.h b/libc/src/stdio/printf_core/printf_main.h index 6a9c9a00265d1..05488ff97f526 100644 --- a/libc/src/stdio/printf_core/printf_main.h +++ b/libc/src/stdio/printf_core/printf_main.h @@ -23,7 +23,7 @@ namespace printf_core { template PrintfResult printf_main(Writer *writer, const char *__restrict str, - internal::ArgList &args) { + internal::ArgList &args) { Parser parser(str, args); int result = 0; for (FormatSection cur_section = parser.get_next_section(); @@ -37,7 +37,7 @@ PrintfResult printf_main(Writer *writer, const char *__restrict str, if (result < 0) return {0, -result}; } - + return writer->get_chars_written(); } diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h index bfc02fedf5244..b96e1afa0b467 100644 --- a/libc/src/stdio/printf_core/vasprintf_internal.h +++ b/libc/src/stdio/printf_core/vasprintf_internal.h @@ -43,8 +43,9 @@ LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) { constexpr size_t DEFAULT_BUFFER_SIZE = 200; -LIBC_INLINE PrintfResult vasprintf_internal(char **ret, const char *__restrict format, - internal::ArgList args) { +LIBC_INLINE PrintfResult vasprintf_internal(char **ret, + const char *__restrict format, + internal::ArgList args) { char init_buff_on_stack[DEFAULT_BUFFER_SIZE]; printf_core::WriteBuffer::value> wb( init_buff_on_stack, DEFAULT_BUFFER_SIZE, resize_overflow_hook); diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index 71a85077e92b8..53a9762606295 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -69,8 +69,8 @@ LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) { } LIBC_INLINE PrintfResult vfprintf_internal(::FILE *__restrict stream, - const char *__restrict format, - internal::ArgList &args) { + const char *__restrict format, + internal::ArgList &args) { constexpr size_t BUFF_SIZE = 1024; char buffer[BUFF_SIZE]; printf_core::WriteBuffer::value> wb( diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp index 8c22935b849a0..6691da1debb5a 100644 --- a/libc/src/stdio/snprintf.cpp +++ b/libc/src/stdio/snprintf.cpp @@ -39,13 +39,13 @@ LLVM_LIBC_FUNCTION(int, snprintf, } if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. wb.buff[wb.buff_cur] = '\0'; - + if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } - - return static_cast(ret_val.value); + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp index 2557197894bec..10db9feb80121 100644 --- a/libc/src/stdio/sprintf.cpp +++ b/libc/src/stdio/sprintf.cpp @@ -43,9 +43,9 @@ LLVM_LIBC_FUNCTION(int, sprintf, if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } - - return static_cast(ret_val.value); + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vasprintf.cpp b/libc/src/stdio/vasprintf.cpp index d8ed3a36c7ecf..11174727e5d64 100644 --- a/libc/src/stdio/vasprintf.cpp +++ b/libc/src/stdio/vasprintf.cpp @@ -26,7 +26,7 @@ LLVM_LIBC_FUNCTION(int, vasprintf, if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } + } return static_cast(ret_val.value); } diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp index f39051cdd4d75..25e6165897674 100644 --- a/libc/src/stdio/vsnprintf.cpp +++ b/libc/src/stdio/vsnprintf.cpp @@ -36,13 +36,13 @@ LLVM_LIBC_FUNCTION(int, vsnprintf, } if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. wb.buff[wb.buff_cur] = '\0'; - + if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } - - return static_cast(ret_val.value); + } + + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp index 4c4a3eefaa7b4..6dda2db250d50 100644 --- a/libc/src/stdio/vsprintf.cpp +++ b/libc/src/stdio/vsprintf.cpp @@ -40,8 +40,8 @@ LLVM_LIBC_FUNCTION(int, vsprintf, if (ret_val.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; - } - return static_cast(ret_val.value); + } + return static_cast(ret_val.value); } } // namespace LIBC_NAMESPACE_DECL From 4761e9a68d279739b4e932331ec3307bdbd4c81f Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Tue, 7 Oct 2025 15:39:17 +0000 Subject: [PATCH 05/25] Fix tests --- libc/src/stdlib/strfromd.cpp | 2 +- .../src/stdio/printf_core/converter_test.cpp | 30 ++++++++--------- .../src/stdio/printf_core/writer_test.cpp | 32 +++++++++---------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp index c0989f1a97dca..b35e476086691 100644 --- a/libc/src/stdlib/strfromd.cpp +++ b/libc/src/stdlib/strfromd.cpp @@ -28,7 +28,7 @@ LLVM_LIBC_FUNCTION(int, strfromd, if (section.has_conv) result = internal::strfromfloat_convert(&writer, section); else - result = writer.write(section.raw_string); + result = writer.write(section.raw_string); // TODO everywhere where writer is used, set errno and ret -1 if (result < 0) return result; diff --git a/libc/test/src/stdio/printf_core/converter_test.cpp b/libc/test/src/stdio/printf_core/converter_test.cpp index bf088937e4104..2dae2a22c864c 100644 --- a/libc/test/src/stdio/printf_core/converter_test.cpp +++ b/libc/test/src/stdio/printf_core/converter_test.cpp @@ -38,7 +38,7 @@ TEST_F(LlvmLibcPrintfConverterTest, SimpleRawConversion) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "abc"); - ASSERT_EQ(writer.get_chars_written(), 3); + ASSERT_EQ(writer.get_chars_written(), size_t{3}); } TEST_F(LlvmLibcPrintfConverterTest, PercentConversion) { @@ -52,7 +52,7 @@ TEST_F(LlvmLibcPrintfConverterTest, PercentConversion) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "%"); - ASSERT_EQ(writer.get_chars_written(), 1); + ASSERT_EQ(writer.get_chars_written(), size_t{1}); } TEST_F(LlvmLibcPrintfConverterTest, CharConversionSimple) { @@ -70,7 +70,7 @@ TEST_F(LlvmLibcPrintfConverterTest, CharConversionSimple) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "D"); - ASSERT_EQ(writer.get_chars_written(), 1); + ASSERT_EQ(writer.get_chars_written(), size_t{1}); } TEST_F(LlvmLibcPrintfConverterTest, CharConversionRightJustified) { @@ -85,7 +85,7 @@ TEST_F(LlvmLibcPrintfConverterTest, CharConversionRightJustified) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, " E"); - ASSERT_EQ(writer.get_chars_written(), 4); + ASSERT_EQ(writer.get_chars_written(), size_t{4}); } TEST_F(LlvmLibcPrintfConverterTest, CharConversionLeftJustified) { @@ -102,7 +102,7 @@ TEST_F(LlvmLibcPrintfConverterTest, CharConversionLeftJustified) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "F "); - ASSERT_EQ(writer.get_chars_written(), 4); + ASSERT_EQ(writer.get_chars_written(), size_t{4}); } TEST_F(LlvmLibcPrintfConverterTest, StringConversionSimple) { @@ -118,7 +118,7 @@ TEST_F(LlvmLibcPrintfConverterTest, StringConversionSimple) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "DEF"); - ASSERT_EQ(writer.get_chars_written(), 3); + ASSERT_EQ(writer.get_chars_written(), size_t{3}); } TEST_F(LlvmLibcPrintfConverterTest, StringConversionPrecisionHigh) { @@ -133,7 +133,7 @@ TEST_F(LlvmLibcPrintfConverterTest, StringConversionPrecisionHigh) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "456"); - ASSERT_EQ(writer.get_chars_written(), 3); + ASSERT_EQ(writer.get_chars_written(), size_t{3}); } TEST_F(LlvmLibcPrintfConverterTest, StringConversionPrecisionLow) { @@ -148,7 +148,7 @@ TEST_F(LlvmLibcPrintfConverterTest, StringConversionPrecisionLow) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "xy"); - ASSERT_EQ(writer.get_chars_written(), 2); + ASSERT_EQ(writer.get_chars_written(), size_t{2}); } TEST_F(LlvmLibcPrintfConverterTest, StringConversionRightJustified) { @@ -163,7 +163,7 @@ TEST_F(LlvmLibcPrintfConverterTest, StringConversionRightJustified) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, " 789"); - ASSERT_EQ(writer.get_chars_written(), 4); + ASSERT_EQ(writer.get_chars_written(), size_t{4}); } TEST_F(LlvmLibcPrintfConverterTest, StringConversionLeftJustified) { @@ -180,7 +180,7 @@ TEST_F(LlvmLibcPrintfConverterTest, StringConversionLeftJustified) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "ghi "); - ASSERT_EQ(writer.get_chars_written(), 4); + ASSERT_EQ(writer.get_chars_written(), size_t{4}); } TEST_F(LlvmLibcPrintfConverterTest, IntConversionSimple) { @@ -194,7 +194,7 @@ TEST_F(LlvmLibcPrintfConverterTest, IntConversionSimple) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "12345"); - ASSERT_EQ(writer.get_chars_written(), 5); + ASSERT_EQ(writer.get_chars_written(), size_t{5}); } TEST_F(LlvmLibcPrintfConverterTest, HexConversion) { @@ -211,7 +211,7 @@ TEST_F(LlvmLibcPrintfConverterTest, HexConversion) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "0x00000000123456ab"); - ASSERT_EQ(writer.get_chars_written(), 18); + ASSERT_EQ(writer.get_chars_written(), size_t{18}); } TEST_F(LlvmLibcPrintfConverterTest, BinaryConversion) { @@ -225,7 +225,7 @@ TEST_F(LlvmLibcPrintfConverterTest, BinaryConversion) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "101010"); - ASSERT_EQ(writer.get_chars_written(), 6); + ASSERT_EQ(writer.get_chars_written(), size_t{6}); } TEST_F(LlvmLibcPrintfConverterTest, PointerConversion) { @@ -239,7 +239,7 @@ TEST_F(LlvmLibcPrintfConverterTest, PointerConversion) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "0x123456ab"); - ASSERT_EQ(writer.get_chars_written(), 10); + ASSERT_EQ(writer.get_chars_written(), size_t{10}); } TEST_F(LlvmLibcPrintfConverterTest, OctConversion) { @@ -253,5 +253,5 @@ TEST_F(LlvmLibcPrintfConverterTest, OctConversion) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ(str, "1234"); - ASSERT_EQ(writer.get_chars_written(), 4); + ASSERT_EQ(writer.get_chars_written(), size_t{4}); } diff --git a/libc/test/src/stdio/printf_core/writer_test.cpp b/libc/test/src/stdio/printf_core/writer_test.cpp index d036341be7981..d263cf55aa474 100644 --- a/libc/test/src/stdio/printf_core/writer_test.cpp +++ b/libc/test/src/stdio/printf_core/writer_test.cpp @@ -39,7 +39,7 @@ TEST(LlvmLibcPrintfWriterTest, Write) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ("abc", str); - ASSERT_EQ(writer.get_chars_written(), 3); + ASSERT_EQ(writer.get_chars_written(), size_t{3}); } TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) { @@ -53,7 +53,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ("abcDEF123", str); - ASSERT_EQ(writer.get_chars_written(), 9); + ASSERT_EQ(writer.get_chars_written(), size_t{9}); } TEST(LlvmLibcPrintfWriterTest, WriteChars) { @@ -66,7 +66,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteChars) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ("aaa", str); - ASSERT_EQ(writer.get_chars_written(), 3); + ASSERT_EQ(writer.get_chars_written(), size_t{3}); } TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) { @@ -80,7 +80,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ("aaaDDD111", str); - ASSERT_EQ(writer.get_chars_written(), 9); + ASSERT_EQ(writer.get_chars_written(), size_t{9}); } TEST(LlvmLibcPrintfWriterTest, WriteManyChars) { @@ -102,7 +102,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteManyChars) { "ZZZZZZZZZZ" "ZZZZZZZZZ", str); - ASSERT_EQ(writer.get_chars_written(), 99); + ASSERT_EQ(writer.get_chars_written(), size_t{99}); } TEST(LlvmLibcPrintfWriterTest, MixedWrites) { @@ -117,7 +117,7 @@ TEST(LlvmLibcPrintfWriterTest, MixedWrites) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ("aaaDEF111456", str); - ASSERT_EQ(writer.get_chars_written(), 12); + ASSERT_EQ(writer.get_chars_written(), size_t{12}); } TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) { @@ -129,7 +129,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ("abcDEF1234", str); - ASSERT_EQ(writer.get_chars_written(), 12); + ASSERT_EQ(writer.get_chars_written(), size_t{12}); } TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) { @@ -141,7 +141,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ("1111111111", str); - ASSERT_EQ(writer.get_chars_written(), 15); + ASSERT_EQ(writer.get_chars_written(), size_t{15}); } TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLength) { @@ -157,7 +157,7 @@ TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLength) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ("aaaDEF1114", str); - ASSERT_EQ(writer.get_chars_written(), 12); + ASSERT_EQ(writer.get_chars_written(), size_t{12}); } TEST(LlvmLibcPrintfWriterTest, StringWithMaxLengthOne) { @@ -175,7 +175,7 @@ TEST(LlvmLibcPrintfWriterTest, StringWithMaxLengthOne) { wb.buff[wb.buff_cur] = '\0'; ASSERT_STREQ("", str); - ASSERT_EQ(writer.get_chars_written(), 12); + ASSERT_EQ(writer.get_chars_written(), size_t{12}); } TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLength) { @@ -187,7 +187,7 @@ TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLength) { writer.write('1', 3); writer.write({"456", 3}); - ASSERT_EQ(writer.get_chars_written(), 12); + ASSERT_EQ(writer.get_chars_written(), size_t{12}); } struct OutBuff { @@ -226,7 +226,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLengthWithCallback) { str[out_buff.cur_pos] = '\0'; ASSERT_STREQ("abcDEF123456", str); - ASSERT_EQ(writer.get_chars_written(), 12); + ASSERT_EQ(writer.get_chars_written(), size_t{12}); } TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLengthWithCallback) { @@ -246,7 +246,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLengthWithCallback) { str[out_buff.cur_pos] = '\0'; ASSERT_STREQ("111111111111111", str); - ASSERT_EQ(writer.get_chars_written(), 15); + ASSERT_EQ(writer.get_chars_written(), size_t{15}); } TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLengthWithCallback) { @@ -269,7 +269,7 @@ TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLengthWithCallback) { str[out_buff.cur_pos] = '\0'; ASSERT_STREQ("aaaDEF111456", str); - ASSERT_EQ(writer.get_chars_written(), 12); + ASSERT_EQ(writer.get_chars_written(), size_t{12}); } TEST(LlvmLibcPrintfWriterTest, ZeroLengthBufferWithCallback) { @@ -292,7 +292,7 @@ TEST(LlvmLibcPrintfWriterTest, ZeroLengthBufferWithCallback) { str[out_buff.cur_pos] = '\0'; ASSERT_STREQ("aaaDEF111456", str); - ASSERT_EQ(writer.get_chars_written(), 12); + ASSERT_EQ(writer.get_chars_written(), size_t{12}); } TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLengthWithCallback) { @@ -312,7 +312,7 @@ TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLengthWithCallback) { wb.overflow_write(""); str[out_buff.cur_pos] = '\0'; - ASSERT_EQ(writer.get_chars_written(), 12); + ASSERT_EQ(writer.get_chars_written(), size_t{12}); ASSERT_STREQ("aaaDEF111456", str); } From 1dd65af1dae8b5a55305b1881f3dbc30163c0724 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Tue, 7 Oct 2025 16:28:29 +0000 Subject: [PATCH 06/25] Add IO error test cases for file variants --- libc/src/stdio/printf_core/vasprintf_internal.h | 4 ++-- libc/test/src/stdio/CMakeLists.txt | 2 ++ libc/test/src/stdio/fprintf_test.cpp | 5 +++++ libc/test/src/stdio/vfprintf_test.cpp | 5 +++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h index b96e1afa0b467..f84f60bec2fc6 100644 --- a/libc/src/stdio/printf_core/vasprintf_internal.h +++ b/libc/src/stdio/printf_core/vasprintf_internal.h @@ -59,12 +59,12 @@ LIBC_INLINE PrintfResult vasprintf_internal(char **ret, if (wb.buff == init_buff_on_stack) { *ret = static_cast(malloc(ret_val.value + 1)); if (ret == nullptr) - return -ENOMEM; + return {0, ENOMEM}; inline_memcpy(*ret, wb.buff, ret_val.value); } else { *ret = wb.buff; } - (*ret)[ret_val.value] = '\0'; // TODO OK HERE or overflow + (*ret)[ret_val.value] = '\0'; return ret_val; } } // namespace printf_core diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt index eec108bc12ca5..d71f1dff11943 100644 --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -186,6 +186,8 @@ add_libc_test( fprintf_test.cpp DEPENDS libc.src.stdio.fprintf + libc.test.UnitTest.ErrnoCheckingTest + libc.test.UnitTest.ErrnoSetterMatcher ${fprintf_test_deps} COMPILE_OPTIONS ${use_system_file} diff --git a/libc/test/src/stdio/fprintf_test.cpp b/libc/test/src/stdio/fprintf_test.cpp index 6799323cc6ad9..3a764e102dc71 100644 --- a/libc/test/src/stdio/fprintf_test.cpp +++ b/libc/test/src/stdio/fprintf_test.cpp @@ -16,6 +16,8 @@ #include "src/stdio/fprintf.h" #include "test/UnitTest/Test.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" namespace printf_test { #ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE @@ -31,6 +33,8 @@ using ::fread; #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace printf_test +using LlvmLibcFPrintfTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + TEST(LlvmLibcFPrintfTest, WriteToFile) { const char *FILENAME = APPEND_LIBC_TEST("fprintf_output.test"); auto FILE_PATH = libc_make_test_file_path(FILENAME); @@ -78,6 +82,7 @@ TEST(LlvmLibcFPrintfTest, WriteToFile) { written = LIBC_NAMESPACE::fprintf(file, "Writing to a read only file should fail."); EXPECT_LT(written, 0); + ASSERT_ERRNO_EQ(EIO); ASSERT_EQ(printf_test::fclose(file), 0); } diff --git a/libc/test/src/stdio/vfprintf_test.cpp b/libc/test/src/stdio/vfprintf_test.cpp index f50565a0f68ca..43240ce13cc96 100644 --- a/libc/test/src/stdio/vfprintf_test.cpp +++ b/libc/test/src/stdio/vfprintf_test.cpp @@ -20,6 +20,8 @@ #include "src/stdio/vfprintf.h" #include "test/UnitTest/Test.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" namespace printf_test { #ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE @@ -44,6 +46,8 @@ int call_vfprintf(::FILE *__restrict stream, const char *__restrict format, return ret; } +using LlvmLibcVFPrintfTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + TEST(LlvmLibcVFPrintfTest, WriteToFile) { const char *FILENAME = APPEND_LIBC_TEST("vfprintf_output.test"); auto FILE_PATH = libc_make_test_file_path(FILENAME); @@ -90,6 +94,7 @@ TEST(LlvmLibcVFPrintfTest, WriteToFile) { written = call_vfprintf(file, "Writing to a read only file should fail."); EXPECT_LT(written, 0); + ASSERT_ERRNO_EQ(EIO); ASSERT_EQ(printf_test::fclose(file), 0); } From ef55545a80b33bbd2947514f4a081b993b389c0e Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Tue, 7 Oct 2025 17:17:50 +0000 Subject: [PATCH 07/25] Add overflow test for fprintf --- libc/test/src/stdio/CMakeLists.txt | 1 + libc/test/src/stdio/fprintf_test.cpp | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt index d71f1dff11943..b513007cdf7c6 100644 --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -169,6 +169,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdio.ferror libc.src.stdio.fopen libc.src.stdio.fread + libc.src.stdio.fopencookie ) # This is to be used for tests which write to libc's platform streams # under full build but write to system-lib's streams otherwise. diff --git a/libc/test/src/stdio/fprintf_test.cpp b/libc/test/src/stdio/fprintf_test.cpp index 3a764e102dc71..6d52611ae98b1 100644 --- a/libc/test/src/stdio/fprintf_test.cpp +++ b/libc/test/src/stdio/fprintf_test.cpp @@ -10,25 +10,29 @@ #include "src/stdio/fclose.h" #include "src/stdio/ferror.h" #include "src/stdio/fopen.h" +#include "src/stdio/fopencookie.h" #include "src/stdio/fread.h" #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE #include "src/stdio/fprintf.h" -#include "test/UnitTest/Test.h" +#include "src/__support/CPP/limits.h" #include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/Test.h" namespace printf_test { #ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE using LIBC_NAMESPACE::fclose; using LIBC_NAMESPACE::ferror; using LIBC_NAMESPACE::fopen; +using LIBC_NAMESPACE::fopencookie; using LIBC_NAMESPACE::fread; #else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) using ::fclose; using ::ferror; using ::fopen; +using ::fopencookie; using ::fread; #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace printf_test @@ -86,3 +90,25 @@ TEST(LlvmLibcFPrintfTest, WriteToFile) { ASSERT_EQ(printf_test::fclose(file), 0); } + +struct NoopStream {}; + +static ssize_t noop_write(void *, const char *, size_t size) { return size; } + +TEST(LlvmLibcFPrintfTest, CharsWrittenOverflow) { + NoopStream stream; + cookie_io_functions_t funcs = {nullptr, &noop_write, nullptr, nullptr}; + ::FILE *file = printf_test::fopencookie(&stream, "w", funcs); + ASSERT_NE(file, nullptr); + + // Trigger an overflow in the return value of fprintf by writing more than + // INT_MAX bytes. We do this by printing a string with precision INT_MAX, and + // then one more character. + int max_int = LIBC_NAMESPACE::cpp::numeric_limits::max(); + int result = LIBC_NAMESPACE::fprintf(file, "%*sA", max_int, ""); + + EXPECT_LT(result, 0); + ASSERT_ERRNO_EQ(EOVERFLOW); + + EXPECT_EQ(printf_test::fclose(file), 0); +} \ No newline at end of file From 63c710b793e4bcfe1b6401aeb5c0843e45ae9150 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Tue, 7 Oct 2025 18:19:56 +0000 Subject: [PATCH 08/25] Cleanup --- libc/src/stdio/baremetal/printf.cpp | 2 +- libc/src/stdio/baremetal/vprintf.cpp | 4 ++-- libc/src/stdio/printf_core/core_structs.h | 2 +- libc/src/stdio/printf_core/printf_main.h | 4 ++-- libc/src/time/strftime_core/strftime_main.h | 2 +- libc/test/src/stdio/fprintf_test.cpp | 11 ++++++----- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index 7253c6549a4e4..6f4ebb35d4004 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -47,7 +47,7 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { int flushval = wb.overflow_write(""); if (flushval != printf_core::WRITE_OK) retval = flushval; - + return retval; } diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index ab02533f14911..4401ddbe8690e 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -22,7 +22,7 @@ namespace LIBC_NAMESPACE_DECL { namespace { LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) { - write_to_stdout(new_str); + write_to_stdout(new_str); return printf_core::WRITE_OK; } @@ -40,7 +40,7 @@ LLVM_LIBC_FUNCTION(int, vprintf, buffer, BUFF_SIZE, &stdout_write_hook, nullptr); printf_core::Writer writer(wb); - int retval = printf_core::printf_main(&writer, format, args); + int retval = printf_core::printf_main(&writer, format, args); // TODO baremetal stuff int flushval = wb.overflow_write(""); if (flushval != printf_core::WRITE_OK) diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index e397e4a5b3abe..22b674da789a5 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -31,7 +31,7 @@ struct PrintfResult { constexpr bool has_error() { return error != 0; } - constexpr operator size_t() { return value; } + // constexpr operator size_t() { return value; } }; // These length modifiers match the length modifiers in the format string, which diff --git a/libc/src/stdio/printf_core/printf_main.h b/libc/src/stdio/printf_core/printf_main.h index 05488ff97f526..7bb5b3f3d1cf5 100644 --- a/libc/src/stdio/printf_core/printf_main.h +++ b/libc/src/stdio/printf_core/printf_main.h @@ -30,9 +30,9 @@ PrintfResult printf_main(Writer *writer, const char *__restrict str, !cur_section.raw_string.empty(); cur_section = parser.get_next_section()) { if (cur_section.has_conv) - result = convert(writer, cur_section); + result = convert(writer, cur_section); // look at usages else - result = writer->write(cur_section.raw_string); + result = writer->write(cur_section.raw_string); // look at usages if (result < 0) return {0, -result}; diff --git a/libc/src/time/strftime_core/strftime_main.h b/libc/src/time/strftime_core/strftime_main.h index c7e590627094a..a97e00dfd9b64 100644 --- a/libc/src/time/strftime_core/strftime_main.h +++ b/libc/src/time/strftime_core/strftime_main.h @@ -36,7 +36,7 @@ int strftime_main(printf_core::Writer *writer, return result; } - return writer->get_chars_written(); + return static_cast(writer->get_chars_written()); } } // namespace strftime_core diff --git a/libc/test/src/stdio/fprintf_test.cpp b/libc/test/src/stdio/fprintf_test.cpp index 6d52611ae98b1..53d056da1f36d 100644 --- a/libc/test/src/stdio/fprintf_test.cpp +++ b/libc/test/src/stdio/fprintf_test.cpp @@ -91,13 +91,14 @@ TEST(LlvmLibcFPrintfTest, WriteToFile) { ASSERT_EQ(printf_test::fclose(file), 0); } -struct NoopStream {}; - -static ssize_t noop_write(void *, const char *, size_t size) { return size; } - TEST(LlvmLibcFPrintfTest, CharsWrittenOverflow) { + struct NoopStream {}; + auto noop_write = [](void *cookie, const char *buf, size_t size) -> ssize_t { + return size; + }; + NoopStream stream; - cookie_io_functions_t funcs = {nullptr, &noop_write, nullptr, nullptr}; + cookie_io_functions_t funcs = {nullptr, +noop_write, nullptr, nullptr}; ::FILE *file = printf_test::fopencookie(&stream, "w", funcs); ASSERT_NE(file, nullptr); From e035a15cb26c61de8ee052a8e8758856a4ebb56d Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Wed, 8 Oct 2025 16:03:09 +0000 Subject: [PATCH 09/25] Add overflow test for vfprintf --- libc/test/src/stdio/vfprintf_test.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/libc/test/src/stdio/vfprintf_test.cpp b/libc/test/src/stdio/vfprintf_test.cpp index 43240ce13cc96..6664d500f2816 100644 --- a/libc/test/src/stdio/vfprintf_test.cpp +++ b/libc/test/src/stdio/vfprintf_test.cpp @@ -15,6 +15,7 @@ #include "src/stdio/ferror.h" #include "src/stdio/fopen.h" #include "src/stdio/fread.h" +#include "src/stdio/fopencookie.h" #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE #include "src/stdio/vfprintf.h" @@ -29,11 +30,13 @@ using LIBC_NAMESPACE::fclose; using LIBC_NAMESPACE::ferror; using LIBC_NAMESPACE::fopen; using LIBC_NAMESPACE::fread; +using LIBC_NAMESPACE::fopencookie; #else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) using ::fclose; using ::ferror; using ::fopen; using ::fread; +using ::fopencookie; #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace printf_test @@ -98,3 +101,26 @@ TEST(LlvmLibcVFPrintfTest, WriteToFile) { ASSERT_EQ(printf_test::fclose(file), 0); } + +TEST(LlvmLibcVFPrintfTest, CharsWrittenOverflow) { + struct NoopStream {}; + auto noop_write = [](void *cookie, const char *buf, size_t size) -> ssize_t { + return size; + }; + + NoopStream stream; + cookie_io_functions_t funcs = {nullptr, +noop_write, nullptr, nullptr}; + ::FILE *file = printf_test::fopencookie(&stream, "w", funcs); + ASSERT_NE(file, nullptr); + + // Trigger an overflow in the return value of vfprintf by writing more than + // INT_MAX bytes. We do this by printing a string with precision INT_MAX, and + // then one more character. + int max_int = LIBC_NAMESPACE::cpp::numeric_limits::max(); + int result = call_vfprintf(file, "%*sA", max_int, ""); + + EXPECT_LT(result, 0); + ASSERT_ERRNO_EQ(EOVERFLOW); + + EXPECT_EQ(printf_test::fclose(file), 0); +} From 56d69681324d3d49f1c156ed8341b3a68e447b1e Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Wed, 8 Oct 2025 16:25:14 +0000 Subject: [PATCH 10/25] Baremetal stuff --- libc/src/stdio/baremetal/printf.cpp | 21 ++++++++++++++----- libc/src/stdio/baremetal/vprintf.cpp | 20 ++++++++++++++---- .../src/stdio/printf_core/vfprintf_internal.h | 4 ++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index 6f4ebb35d4004..58ff12ba125ea 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -42,13 +42,24 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { buffer, BUFF_SIZE, &stdout_write_hook, nullptr); printf_core::Writer writer(wb); - int retval = printf_core::printf_main(&writer, format, args); + auto retval = printf_core::printf_main(&writer, format, args); + if (retval.has_error()) { + libc_errno = retval.error; + return -1; + } int flushval = wb.overflow_write(""); - if (flushval != printf_core::WRITE_OK) - retval = flushval; - - return retval; + if (flushval != printf_core::WRITE_OK) { + libc_errno = -flushval; + return -1; + } + + if (retval.value >= cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(retval.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index 4401ddbe8690e..7dcf01280685f 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -40,13 +40,25 @@ LLVM_LIBC_FUNCTION(int, vprintf, buffer, BUFF_SIZE, &stdout_write_hook, nullptr); printf_core::Writer writer(wb); - int retval = printf_core::printf_main(&writer, format, args); // TODO baremetal stuff + auto retval = printf_core::printf_main(&writer, format, args); + if (retval.has_error()) { + libc_errno = retval.error; + return -1; + } int flushval = wb.overflow_write(""); - if (flushval != printf_core::WRITE_OK) - retval = flushval; + if (flushval != printf_core::WRITE_OK) { + libc_errno = -flushval; + return -1; + + } - return retval; + if (retval.value >= cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } + + return static_cast(retval.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index 53a9762606295..c50cacf2709a7 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -78,6 +78,10 @@ LIBC_INLINE PrintfResult vfprintf_internal(::FILE *__restrict stream, Writer writer(wb); internal::flockfile(stream); auto retval = printf_main(&writer, format, args); + if (retval.has_error()) { + internal::funlockfile(stream); + return retval; + } int flushval = wb.overflow_write(""); if (flushval != WRITE_OK) retval.error = -flushval; From 995bb08795001429bdd18f784ca005684805a076 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Wed, 8 Oct 2025 16:42:05 +0000 Subject: [PATCH 11/25] Add test for nullptr write error --- libc/src/stdio/printf_core/core_structs.h | 8 -------- libc/test/src/stdio/fprintf_test.cpp | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index 22b674da789a5..ab6c9228fd76f 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -144,14 +144,6 @@ template LIBC_INLINE constexpr TypeDesc type_desc_from_type() { // This is the value to be returned by conversions when no error has occurred. constexpr int WRITE_OK = 0; -// These are the printf return values for when an error has occurred. They are -// all negative, and should be distinct. -// constexpr int FILE_WRITE_ERROR = -1; -// constexpr int FILE_STATUS_ERROR = -2; -// constexpr int NULLPTR_WRITE_ERROR = -3; -// constexpr int INT_CONVERSION_ERROR = -4; -// constexpr int FIXED_POINT_CONVERSION_ERROR = -5; -// constexpr int ALLOCATION_ERROR = -6; } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/stdio/fprintf_test.cpp b/libc/test/src/stdio/fprintf_test.cpp index 53d056da1f36d..f80077fd0885d 100644 --- a/libc/test/src/stdio/fprintf_test.cpp +++ b/libc/test/src/stdio/fprintf_test.cpp @@ -112,4 +112,20 @@ TEST(LlvmLibcFPrintfTest, CharsWrittenOverflow) { ASSERT_ERRNO_EQ(EOVERFLOW); EXPECT_EQ(printf_test::fclose(file), 0); -} \ No newline at end of file +} + +#ifndef LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS +TEST(LlvmLibcFPrintfTest, NullPtrCheck) { + const char *FILENAME = APPEND_LIBC_TEST("fprintf_nullptr.test"); + auto FILE_PATH = libc_make_test_file_path(FILENAME); + + ::FILE *file = printf_test::fopen(FILE_PATH, "w"); + ASSERT_FALSE(file == nullptr); + + int ret = LIBC_NAMESPACE::fprintf(file, "hello %n", (int *)nullptr); + EXPECT_LT(ret, 0); + ASSERT_ERRNO_EQ(EINVAL); + + ASSERT_EQ(printf_test::fclose(file), 0); +} +#endif // LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS From eedbad9782d5f9368334be8064e3a1d34847686b Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Wed, 8 Oct 2025 18:44:12 +0000 Subject: [PATCH 12/25] Add overflow handling to strfrom functions --- libc/src/stdlib/strfromd.cpp | 5 ++++- libc/src/stdlib/strfromf.cpp | 5 ++++- libc/src/stdlib/strfroml.cpp | 5 ++++- libc/src/time/strftime_core/strftime_main.h | 1 + libc/test/src/stdlib/StrfromTest.h | 20 ++++++++++++++++++-- 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp index b35e476086691..2ef8d7e7bdd64 100644 --- a/libc/src/stdlib/strfromd.cpp +++ b/libc/src/stdlib/strfromd.cpp @@ -36,7 +36,10 @@ LLVM_LIBC_FUNCTION(int, strfromd, if (n > 0) wb.buff[wb.buff_cur] = '\0'; - // TODO overflow + if (writer.get_chars_written() > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } return static_cast(writer.get_chars_written()); } diff --git a/libc/src/stdlib/strfromf.cpp b/libc/src/stdlib/strfromf.cpp index 01090c997af1b..5c3e95f4146f2 100644 --- a/libc/src/stdlib/strfromf.cpp +++ b/libc/src/stdlib/strfromf.cpp @@ -36,7 +36,10 @@ LLVM_LIBC_FUNCTION(int, strfromf, if (n > 0) wb.buff[wb.buff_cur] = '\0'; - // TODO overflow + if (writer.get_chars_written() > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } return static_cast(writer.get_chars_written()); } diff --git a/libc/src/stdlib/strfroml.cpp b/libc/src/stdlib/strfroml.cpp index 436243d1e1c38..1605e8ab7c18f 100644 --- a/libc/src/stdlib/strfroml.cpp +++ b/libc/src/stdlib/strfroml.cpp @@ -41,7 +41,10 @@ LLVM_LIBC_FUNCTION(int, strfroml, if (n > 0) wb.buff[wb.buff_cur] = '\0'; - // TODO overflow + if (writer.get_chars_written() > cpp::numeric_limits::max()) { + libc_errno = EOVERFLOW; + return -1; + } return static_cast(writer.get_chars_written()); } diff --git a/libc/src/time/strftime_core/strftime_main.h b/libc/src/time/strftime_core/strftime_main.h index a97e00dfd9b64..865433b8b54c9 100644 --- a/libc/src/time/strftime_core/strftime_main.h +++ b/libc/src/time/strftime_core/strftime_main.h @@ -36,6 +36,7 @@ int strftime_main(printf_core::Writer *writer, return result; } + // TODO could work similar to printf, retval is size_t in libc outer func return static_cast(writer->get_chars_written()); } diff --git a/libc/test/src/stdlib/StrfromTest.h b/libc/test/src/stdlib/StrfromTest.h index e82c94499aa11..f24178b2366c9 100644 --- a/libc/test/src/stdlib/StrfromTest.h +++ b/libc/test/src/stdlib/StrfromTest.h @@ -6,16 +6,19 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/CPP/limits.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" #include "test/UnitTest/Test.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" #define ASSERT_STREQ_LEN(actual_written, actual_str, expected_str) \ EXPECT_EQ(actual_written, static_cast(sizeof(expected_str) - 1)); \ EXPECT_STREQ(actual_str, expected_str); template -class StrfromTest : public LIBC_NAMESPACE::testing::Test { +class StrfromTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest { static constexpr bool is_single_prec = LIBC_NAMESPACE::cpp::is_same::value; @@ -481,6 +484,16 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test { written = func(buff, 10, "%A", -ld_nan); ASSERT_STREQ_LEN(written, buff, "-NAN"); } + + void charsWrittenOverflow(FunctionT func) { + char buff[100]; + // Trigger an overflow in the return value of strfrom by writing more than + // INT_MAX bytes. + int result = func(buff, sizeof(buff), "%.2147483647f", 1.0f); + + EXPECT_LT(result, 0); + ASSERT_ERRNO_EQ(EOVERFLOW); + } }; #define STRFROM_TEST(InputType, name, func) \ @@ -501,4 +514,7 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test { TEST_F(LlvmLibc##name##Test, InsufficientBufferSize) { \ insufficentBufsize(func); \ } \ - TEST_F(LlvmLibc##name##Test, InfAndNanValues) { infNanValues(func); } + TEST_F(LlvmLibc##name##Test, InfAndNanValues) { infNanValues(func); } \ + TEST_F(LlvmLibc##name##Test, CharsWrittenOverflow) { \ + charsWrittenOverflow(func); \ + } From 242b75ced96c1263654e4261509aadc6f6c340be Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Fri, 10 Oct 2025 16:00:28 +0000 Subject: [PATCH 13/25] Cleanup --- libc/src/stdio/baremetal/printf.cpp | 2 +- libc/src/stdio/baremetal/vprintf.cpp | 4 ++-- libc/src/stdio/printf_core/core_structs.h | 2 +- libc/src/stdio/printf_core/printf_main.h | 5 ++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index 58ff12ba125ea..e100f946ae9d7 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -54,7 +54,7 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { return -1; } - if (retval.value >= cpp::numeric_limits::max()) { + if (retval.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index 7dcf01280685f..992618d062b0d 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -22,7 +22,7 @@ namespace LIBC_NAMESPACE_DECL { namespace { LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) { - write_to_stdout(new_str); + write_to_stdout(new_str); return printf_core::WRITE_OK; } @@ -53,7 +53,7 @@ LLVM_LIBC_FUNCTION(int, vprintf, } - if (retval.value >= cpp::numeric_limits::max()) { + if (retval.value > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index ab6c9228fd76f..3cb76ed32776f 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -31,7 +31,7 @@ struct PrintfResult { constexpr bool has_error() { return error != 0; } - // constexpr operator size_t() { return value; } + constexpr operator size_t() { return value; } }; // These length modifiers match the length modifiers in the format string, which diff --git a/libc/src/stdio/printf_core/printf_main.h b/libc/src/stdio/printf_core/printf_main.h index 7bb5b3f3d1cf5..f187b43a9cd8f 100644 --- a/libc/src/stdio/printf_core/printf_main.h +++ b/libc/src/stdio/printf_core/printf_main.h @@ -30,10 +30,9 @@ PrintfResult printf_main(Writer *writer, const char *__restrict str, !cur_section.raw_string.empty(); cur_section = parser.get_next_section()) { if (cur_section.has_conv) - result = convert(writer, cur_section); // look at usages + result = convert(writer, cur_section); else - result = writer->write(cur_section.raw_string); // look at usages - + result = writer->write(cur_section.raw_string); if (result < 0) return {0, -result}; } From 492b9f1c02d5c00392d2ec0b718806288c6cd169 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Fri, 10 Oct 2025 16:16:46 +0000 Subject: [PATCH 14/25] Run clang-format --- libc/src/stdio/baremetal/printf.cpp | 2 +- libc/src/stdio/baremetal/vprintf.cpp | 1 - libc/src/stdio/printf_core/fixed_converter.h | 4 ++-- libc/src/stdio/printf_core/int_converter.h | 2 +- libc/src/stdio/printf_core/write_int_converter.h | 2 +- libc/src/stdlib/strfromd.cpp | 3 ++- libc/test/src/stdio/vfprintf_test.cpp | 8 ++++---- libc/test/src/stdlib/StrfromTest.h | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index e100f946ae9d7..a2e308ed54a57 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -59,7 +59,7 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { return -1; } - return static_cast(retval.value); + return static_cast(retval.value); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index 992618d062b0d..003d7d70707fb 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -50,7 +50,6 @@ LLVM_LIBC_FUNCTION(int, vprintf, if (flushval != printf_core::WRITE_OK) { libc_errno = -flushval; return -1; - } if (retval.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/printf_core/fixed_converter.h b/libc/src/stdio/printf_core/fixed_converter.h index a7185dcb11d8a..77384b1891174 100644 --- a/libc/src/stdio/printf_core/fixed_converter.h +++ b/libc/src/stdio/printf_core/fixed_converter.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FIXED_CONVERTER_H #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FIXED_CONVERTER_H +#include "hdr/errno_macros.h" #include "include/llvm-libc-macros/stdfix-macros.h" #include "src/__support/CPP/string_view.h" #include "src/__support/ctype_utils.h" @@ -20,7 +21,6 @@ #include "src/stdio/printf_core/converter_utils.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/writer.h" -#include "hdr/errno_macros.h" #include #include @@ -60,7 +60,7 @@ LIBC_INLINE constexpr uint32_t const_ten_exp(uint32_t exponent) { READ_FX_BITS(unsigned LENGTH_MODIFIER accum); \ } else { \ LIBC_ASSERT(false && "Invalid conversion name passed to convert_fixed"); \ - return -EINVAL; \ + return -EINVAL; \ } \ } while (false) diff --git a/libc/src/stdio/printf_core/int_converter.h b/libc/src/stdio/printf_core/int_converter.h index 08e27e1a60447..554436c9091a8 100644 --- a/libc/src/stdio/printf_core/int_converter.h +++ b/libc/src/stdio/printf_core/int_converter.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H +#include "hdr/errno_macros.h" #include "src/__support/CPP/span.h" #include "src/__support/CPP/string_view.h" #include "src/__support/ctype_utils.h" @@ -17,7 +18,6 @@ #include "src/stdio/printf_core/converter_utils.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/writer.h" -#include "hdr/errno_macros.h" #include #include diff --git a/libc/src/stdio/printf_core/write_int_converter.h b/libc/src/stdio/printf_core/write_int_converter.h index 15c32d9ac272a..b424278c66185 100644 --- a/libc/src/stdio/printf_core/write_int_converter.h +++ b/libc/src/stdio/printf_core/write_int_converter.h @@ -9,10 +9,10 @@ #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITE_INT_CONVERTER_H #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITE_INT_CONVERTER_H +#include "hdr/errno_macros.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/writer.h" -#include "hdr/errno_macros.h" #include #include diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp index 2ef8d7e7bdd64..a0e8bb3ff35f4 100644 --- a/libc/src/stdlib/strfromd.cpp +++ b/libc/src/stdlib/strfromd.cpp @@ -28,7 +28,8 @@ LLVM_LIBC_FUNCTION(int, strfromd, if (section.has_conv) result = internal::strfromfloat_convert(&writer, section); else - result = writer.write(section.raw_string); // TODO everywhere where writer is used, set errno and ret -1 + result = writer.write(section.raw_string); // TODO everywhere where writer + // is used, set errno and ret -1 if (result < 0) return result; diff --git a/libc/test/src/stdio/vfprintf_test.cpp b/libc/test/src/stdio/vfprintf_test.cpp index 6664d500f2816..804adbc26ddda 100644 --- a/libc/test/src/stdio/vfprintf_test.cpp +++ b/libc/test/src/stdio/vfprintf_test.cpp @@ -14,29 +14,29 @@ #include "src/stdio/fclose.h" #include "src/stdio/ferror.h" #include "src/stdio/fopen.h" -#include "src/stdio/fread.h" #include "src/stdio/fopencookie.h" +#include "src/stdio/fread.h" #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE #include "src/stdio/vfprintf.h" -#include "test/UnitTest/Test.h" #include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/Test.h" namespace printf_test { #ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE using LIBC_NAMESPACE::fclose; using LIBC_NAMESPACE::ferror; using LIBC_NAMESPACE::fopen; -using LIBC_NAMESPACE::fread; using LIBC_NAMESPACE::fopencookie; +using LIBC_NAMESPACE::fread; #else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) using ::fclose; using ::ferror; using ::fopen; -using ::fread; using ::fopencookie; +using ::fread; #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace printf_test diff --git a/libc/test/src/stdlib/StrfromTest.h b/libc/test/src/stdlib/StrfromTest.h index f24178b2366c9..1442f172e19fe 100644 --- a/libc/test/src/stdlib/StrfromTest.h +++ b/libc/test/src/stdlib/StrfromTest.h @@ -9,9 +9,9 @@ #include "src/__support/CPP/limits.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" -#include "test/UnitTest/Test.h" #include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/Test.h" #define ASSERT_STREQ_LEN(actual_written, actual_str, expected_str) \ EXPECT_EQ(actual_written, static_cast(sizeof(expected_str) - 1)); \ From 71554f995b01088c595e75ff419b12ed93b75806 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Fri, 10 Oct 2025 16:25:49 +0000 Subject: [PATCH 15/25] Fix unused param error --- libc/src/stdlib/strfromd.cpp | 3 +-- libc/src/time/strftime_core/strftime_main.h | 2 +- libc/test/src/stdio/fprintf_test.cpp | 2 +- libc/test/src/stdio/vfprintf_test.cpp | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp index a0e8bb3ff35f4..c89f611831579 100644 --- a/libc/src/stdlib/strfromd.cpp +++ b/libc/src/stdlib/strfromd.cpp @@ -28,8 +28,7 @@ LLVM_LIBC_FUNCTION(int, strfromd, if (section.has_conv) result = internal::strfromfloat_convert(&writer, section); else - result = writer.write(section.raw_string); // TODO everywhere where writer - // is used, set errno and ret -1 + result = writer.write(section.raw_string); if (result < 0) return result; diff --git a/libc/src/time/strftime_core/strftime_main.h b/libc/src/time/strftime_core/strftime_main.h index 865433b8b54c9..8e369c2710ddb 100644 --- a/libc/src/time/strftime_core/strftime_main.h +++ b/libc/src/time/strftime_core/strftime_main.h @@ -36,7 +36,7 @@ int strftime_main(printf_core::Writer *writer, return result; } - // TODO could work similar to printf, retval is size_t in libc outer func + // TODO: return result struct like printf, so that size_t can be returned return static_cast(writer->get_chars_written()); } diff --git a/libc/test/src/stdio/fprintf_test.cpp b/libc/test/src/stdio/fprintf_test.cpp index f80077fd0885d..9a26c44e7f12c 100644 --- a/libc/test/src/stdio/fprintf_test.cpp +++ b/libc/test/src/stdio/fprintf_test.cpp @@ -93,7 +93,7 @@ TEST(LlvmLibcFPrintfTest, WriteToFile) { TEST(LlvmLibcFPrintfTest, CharsWrittenOverflow) { struct NoopStream {}; - auto noop_write = [](void *cookie, const char *buf, size_t size) -> ssize_t { + auto noop_write = [](void *, const char *, size_t size) -> ssize_t { return size; }; diff --git a/libc/test/src/stdio/vfprintf_test.cpp b/libc/test/src/stdio/vfprintf_test.cpp index 804adbc26ddda..952c55b0b0a85 100644 --- a/libc/test/src/stdio/vfprintf_test.cpp +++ b/libc/test/src/stdio/vfprintf_test.cpp @@ -104,7 +104,7 @@ TEST(LlvmLibcVFPrintfTest, WriteToFile) { TEST(LlvmLibcVFPrintfTest, CharsWrittenOverflow) { struct NoopStream {}; - auto noop_write = [](void *cookie, const char *buf, size_t size) -> ssize_t { + auto noop_write = [](void *, const char *, size_t size) -> ssize_t { return size; }; From b03c5458b42673b508eb107dae64f67934aedc6d Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Sun, 12 Oct 2025 13:16:26 +0000 Subject: [PATCH 16/25] Refactor File to store error_code instead of error flag --- libc/src/__support/File/file.cpp | 56 +++++++++++++++++--------------- libc/src/__support/File/file.h | 12 +++---- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp index 4217e73828388..4df34cbd6c719 100644 --- a/libc/src/__support/File/file.cpp +++ b/libc/src/__support/File/file.cpp @@ -20,7 +20,7 @@ namespace LIBC_NAMESPACE_DECL { FileIOResult File::write_unlocked(const void *data, size_t len) { if (!write_allowed()) { - err = true; + error_code = EBADF; return {0, EBADF}; } @@ -45,16 +45,16 @@ FileIOResult File::write_unlocked_nbf(const uint8_t *data, size_t len) { FileIOResult write_result = platform_write(this, buf, write_size); pos = 0; // Buffer is now empty so reset pos to the beginning. // If less bytes were written than expected, then an error occurred. - if (write_result < write_size) { - err = true; + if (write_result.has_error() || write_result < write_size) { + error_code = write_result.has_error() ? write_result.error : EIO; // No bytes from data were written, so return 0. - return {0, write_result.error}; + return {0, error_code}; } } FileIOResult write_result = platform_write(this, data, len); - if (write_result < len) - err = true; + if (write_result.has_error() || write_result < len) + error_code = write_result.has_error() ? write_result.error : EIO; return write_result; } @@ -106,9 +106,9 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) { // If less bytes were written than expected, then an error occurred. Return // the number of bytes that have been written from |data|. if (buf_result.has_error() || bytes_written < write_size) { - err = true; + error_code = buf_result.has_error() ? buf_result.error : EIO; return {bytes_written <= init_pos ? 0 : bytes_written - init_pos, - buf_result.error}; + error_code}; } // The second piece is handled basically the same as the first, although we @@ -128,8 +128,8 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) { // If less bytes were written than expected, then an error occurred. Return // the number of bytes that have been written from |data|. if (result.has_error() || bytes_written < remainder.size()) { - err = true; - return {primary.size() + bytes_written, result.error}; + error_code = result.has_error() ? result.error : EIO; + return {primary.size() + bytes_written, error_code}; } } @@ -166,18 +166,20 @@ FileIOResult File::write_unlocked_lbf(const uint8_t *data, size_t len) { size_t written = 0; - written = write_unlocked_nbf(primary.data(), primary.size()); - if (written < primary.size()) { - err = true; - return written; + auto write_result = write_unlocked_nbf(primary.data(), primary.size()); + written += write_result; + if (write_result.has_error() || written < primary.size()) { + error_code = write_result.has_error() ? write_result.error : EIO; + return {written, error_code}; } flush_unlocked(); - written += write_unlocked_fbf(remainder.data(), remainder.size()); - if (written < len) { - err = true; - return written; + write_result = write_unlocked_fbf(remainder.data(), remainder.size()); + written += write_result;; + if (write_result.has_error() || written < len) { + error_code = write_result.has_error() ? write_result.error : EIO; + return {written, error_code}; } return len; @@ -185,7 +187,7 @@ FileIOResult File::write_unlocked_lbf(const uint8_t *data, size_t len) { FileIOResult File::read_unlocked(void *data, size_t len) { if (!read_allowed()) { - err = true; + error_code = EBADF; return {0, EBADF}; } @@ -244,7 +246,7 @@ FileIOResult File::read_unlocked_fbf(uint8_t *data, size_t len) { if (!result.has_error()) eof = true; else - err = true; + error_code = result.error; return {available_data + fetched_size, result.error}; } return len; @@ -262,7 +264,7 @@ FileIOResult File::read_unlocked_fbf(uint8_t *data, size_t len) { if (!result.has_error()) eof = true; else - err = true; + error_code = result.error; } return {transfer_size + available_data, result.error}; } @@ -282,7 +284,7 @@ FileIOResult File::read_unlocked_nbf(uint8_t *data, size_t len) { if (!result.has_error()) eof = true; else - err = true; + error_code = result.error; } return {result + available_data, result.error}; } @@ -321,7 +323,7 @@ int File::ungetc_unlocked(int c) { } eof = false; // There is atleast one character that can be read now. - err = false; // This operation was a success. + error_code = 0; // This operation was a success. return c; } @@ -331,8 +333,8 @@ ErrorOr File::seek(off_t offset, int whence) { FileIOResult buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { - err = true; - return Error(buf_result.error); + error_code = buf_result.has_error() ? buf_result.error : EIO; + return Error(error_code); } } else if (prev_op == FileOp::READ && whence == SEEK_CUR) { // More data could have been read out from the platform file than was @@ -369,8 +371,8 @@ int File::flush_unlocked() { if (prev_op == FileOp::WRITE && pos > 0) { FileIOResult buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { - err = true; - return buf_result.error; + error_code = buf_result.has_error() ? buf_result.error : EIO; + return error_code; } pos = 0; } diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h index 3652e448c7f5a..ad3250f1f84bd 100644 --- a/libc/src/__support/File/file.h +++ b/libc/src/__support/File/file.h @@ -118,7 +118,7 @@ class File { size_t read_limit; bool eof; - bool err; + int error_code; // This is a convenience RAII class to lock and unlock file objects. class FileLock { @@ -161,7 +161,7 @@ class File { /*robust=*/false, /*pshared=*/false), ungetc_buf(0), buf(buffer), bufsize(buffer_size), bufmode(buffer_mode), own_buf(owned), mode(modeflags), pos(0), prev_op(FileOp::NONE), - read_limit(0), eof(false), err(false) { + read_limit(0), eof(false), error_code(0) { adjust_buf(); } @@ -214,8 +214,8 @@ class File { if (prev_op == FileOp::WRITE && pos > 0) { auto buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { - err = true; - return buf_result.error; + error_code = buf_result.has_error() ? buf_result.error : EIO; + return error_code; } } } @@ -250,14 +250,14 @@ class File { void lock() { mutex.lock(); } void unlock() { mutex.unlock(); } - bool error_unlocked() const { return err; } + bool error_unlocked() const { return error_code != 0; } bool error() { FileLock l(this); return error_unlocked(); } - void clearerr_unlocked() { err = false; } + void clearerr_unlocked() { error_code = 0; } void clearerr() { FileLock l(this); From 6d05774e8bfb2444ec9fdb48ddf235b930bbcdc7 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Sun, 12 Oct 2025 16:13:35 +0000 Subject: [PATCH 17/25] Map internall err code to errno --- libc/src/__support/File/file.cpp | 46 +++++++++---------- libc/src/__support/File/file.h | 19 +++++--- libc/src/stdio/CMakeLists.txt | 6 +++ libc/src/stdio/asprintf.cpp | 2 +- libc/src/stdio/baremetal/printf.cpp | 4 +- libc/src/stdio/baremetal/vprintf.cpp | 4 +- libc/src/stdio/generic/CMakeLists.txt | 1 + libc/src/stdio/generic/fprintf.cpp | 2 +- libc/src/stdio/generic/printf.cpp | 6 ++- libc/src/stdio/generic/vfprintf.cpp | 3 +- libc/src/stdio/generic/vprintf.cpp | 3 +- libc/src/stdio/printf_core/CMakeLists.txt | 2 + libc/src/stdio/printf_core/core_structs.h | 45 ++++++++++++++++++ libc/src/stdio/printf_core/fixed_converter.h | 2 +- libc/src/stdio/printf_core/int_converter.h | 2 +- .../stdio/printf_core/vasprintf_internal.h | 4 +- .../src/stdio/printf_core/vfprintf_internal.h | 2 +- .../stdio/printf_core/write_int_converter.h | 2 +- libc/src/stdio/snprintf.cpp | 3 +- libc/src/stdio/sprintf.cpp | 3 +- libc/src/stdio/vasprintf.cpp | 3 +- libc/src/stdio/vsnprintf.cpp | 3 +- libc/src/stdio/vsprintf.cpp | 3 +- 23 files changed, 121 insertions(+), 49 deletions(-) diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp index 4df34cbd6c719..b4f0115e09bd2 100644 --- a/libc/src/__support/File/file.cpp +++ b/libc/src/__support/File/file.cpp @@ -20,7 +20,7 @@ namespace LIBC_NAMESPACE_DECL { FileIOResult File::write_unlocked(const void *data, size_t len) { if (!write_allowed()) { - error_code = EBADF; + err_code = EBADF; return {0, EBADF}; } @@ -46,15 +46,15 @@ FileIOResult File::write_unlocked_nbf(const uint8_t *data, size_t len) { pos = 0; // Buffer is now empty so reset pos to the beginning. // If less bytes were written than expected, then an error occurred. if (write_result.has_error() || write_result < write_size) { - error_code = write_result.has_error() ? write_result.error : EIO; + err_code = write_result.has_error() ? write_result.error : EIO; // No bytes from data were written, so return 0. - return {0, error_code}; + return {0, err_code}; } } FileIOResult write_result = platform_write(this, data, len); if (write_result.has_error() || write_result < len) - error_code = write_result.has_error() ? write_result.error : EIO; + err_code = write_result.has_error() ? write_result.error : EIO; return write_result; } @@ -106,9 +106,8 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) { // If less bytes were written than expected, then an error occurred. Return // the number of bytes that have been written from |data|. if (buf_result.has_error() || bytes_written < write_size) { - error_code = buf_result.has_error() ? buf_result.error : EIO; - return {bytes_written <= init_pos ? 0 : bytes_written - init_pos, - error_code}; + err_code = buf_result.has_error() ? buf_result.error : EIO; + return {bytes_written <= init_pos ? 0 : bytes_written - init_pos, err_code}; } // The second piece is handled basically the same as the first, although we @@ -128,8 +127,8 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) { // If less bytes were written than expected, then an error occurred. Return // the number of bytes that have been written from |data|. if (result.has_error() || bytes_written < remainder.size()) { - error_code = result.has_error() ? result.error : EIO; - return {primary.size() + bytes_written, error_code}; + err_code = result.has_error() ? result.error : EIO; + return {primary.size() + bytes_written, err_code}; } } @@ -169,17 +168,18 @@ FileIOResult File::write_unlocked_lbf(const uint8_t *data, size_t len) { auto write_result = write_unlocked_nbf(primary.data(), primary.size()); written += write_result; if (write_result.has_error() || written < primary.size()) { - error_code = write_result.has_error() ? write_result.error : EIO; - return {written, error_code}; + err_code = write_result.has_error() ? write_result.error : EIO; + return {written, err_code}; } flush_unlocked(); write_result = write_unlocked_fbf(remainder.data(), remainder.size()); - written += write_result;; + written += write_result; + ; if (write_result.has_error() || written < len) { - error_code = write_result.has_error() ? write_result.error : EIO; - return {written, error_code}; + err_code = write_result.has_error() ? write_result.error : EIO; + return {written, err_code}; } return len; @@ -187,7 +187,7 @@ FileIOResult File::write_unlocked_lbf(const uint8_t *data, size_t len) { FileIOResult File::read_unlocked(void *data, size_t len) { if (!read_allowed()) { - error_code = EBADF; + err_code = EBADF; return {0, EBADF}; } @@ -246,7 +246,7 @@ FileIOResult File::read_unlocked_fbf(uint8_t *data, size_t len) { if (!result.has_error()) eof = true; else - error_code = result.error; + err_code = result.error; return {available_data + fetched_size, result.error}; } return len; @@ -264,7 +264,7 @@ FileIOResult File::read_unlocked_fbf(uint8_t *data, size_t len) { if (!result.has_error()) eof = true; else - error_code = result.error; + err_code = result.error; } return {transfer_size + available_data, result.error}; } @@ -284,7 +284,7 @@ FileIOResult File::read_unlocked_nbf(uint8_t *data, size_t len) { if (!result.has_error()) eof = true; else - error_code = result.error; + err_code = result.error; } return {result + available_data, result.error}; } @@ -323,7 +323,7 @@ int File::ungetc_unlocked(int c) { } eof = false; // There is atleast one character that can be read now. - error_code = 0; // This operation was a success. + err_code = 0; // This operation was a success. return c; } @@ -333,8 +333,8 @@ ErrorOr File::seek(off_t offset, int whence) { FileIOResult buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { - error_code = buf_result.has_error() ? buf_result.error : EIO; - return Error(error_code); + err_code = buf_result.has_error() ? buf_result.error : EIO; + return Error(err_code); } } else if (prev_op == FileOp::READ && whence == SEEK_CUR) { // More data could have been read out from the platform file than was @@ -371,8 +371,8 @@ int File::flush_unlocked() { if (prev_op == FileOp::WRITE && pos > 0) { FileIOResult buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { - error_code = buf_result.has_error() ? buf_result.error : EIO; - return error_code; + err_code = buf_result.has_error() ? buf_result.error : EIO; + return err_code; } pos = 0; } diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h index ad3250f1f84bd..2f7bfaf1a779a 100644 --- a/libc/src/__support/File/file.h +++ b/libc/src/__support/File/file.h @@ -118,7 +118,7 @@ class File { size_t read_limit; bool eof; - int error_code; + int err_code; // This is a convenience RAII class to lock and unlock file objects. class FileLock { @@ -161,7 +161,7 @@ class File { /*robust=*/false, /*pshared=*/false), ungetc_buf(0), buf(buffer), bufsize(buffer_size), bufmode(buffer_mode), own_buf(owned), mode(modeflags), pos(0), prev_op(FileOp::NONE), - read_limit(0), eof(false), error_code(0) { + read_limit(0), eof(false), err_code(0) { adjust_buf(); } @@ -214,8 +214,8 @@ class File { if (prev_op == FileOp::WRITE && pos > 0) { auto buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { - error_code = buf_result.has_error() ? buf_result.error : EIO; - return error_code; + err_code = buf_result.has_error() ? buf_result.error : EIO; + return err_code; } } } @@ -250,14 +250,21 @@ class File { void lock() { mutex.lock(); } void unlock() { mutex.unlock(); } - bool error_unlocked() const { return error_code != 0; } + bool error_unlocked() const { return err_code != 0; } bool error() { FileLock l(this); return error_unlocked(); } - void clearerr_unlocked() { error_code = 0; } + int error_code_unlocked() const { return err_code; } + + int error_code() { + FileLock l(this); + return error_code_unlocked(); + } + + void clearerr_unlocked() { err_code = 0; } void clearerr() { FileLock l(this); diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt index b0a6ef1e291b5..d7af6c47efbc8 100644 --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -125,6 +125,7 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer + libc.src.stdio.printf_core.core_structs ) add_entrypoint_object( @@ -136,6 +137,7 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer + libc.src.stdio.printf_core.core_structs ) add_entrypoint_object( @@ -146,6 +148,7 @@ add_entrypoint_object( asprintf.h DEPENDS libc.src.stdio.printf_core.vasprintf_internal + libc.src.stdio.printf_core.core_structs ) add_entrypoint_object( @@ -157,6 +160,7 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer + libc.src.stdio.printf_core.core_structs ) add_entrypoint_object( @@ -168,6 +172,7 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer + libc.src.stdio.printf_core.core_structs ) add_entrypoint_object( @@ -178,6 +183,7 @@ add_entrypoint_object( vasprintf.h DEPENDS libc.src.stdio.printf_core.vasprintf_internal + libc.src.stdio.printf_core.core_structs ) add_subdirectory(printf_core) diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp index 13c1ee68ef0f2..014cf7efade6b 100644 --- a/libc/src/stdio/asprintf.cpp +++ b/libc/src/stdio/asprintf.cpp @@ -24,7 +24,7 @@ LLVM_LIBC_FUNCTION(int, asprintf, va_end(vlist); auto ret_val = printf_core::vasprintf_internal(buffer, format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; } if (ret_val.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index a2e308ed54a57..5ac9433152ee9 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -44,13 +44,13 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { auto retval = printf_core::printf_main(&writer, format, args); if (retval.has_error()) { - libc_errno = retval.error; + libc_errno = retval.error; // TODO map return -1; } int flushval = wb.overflow_write(""); if (flushval != printf_core::WRITE_OK) { - libc_errno = -flushval; + libc_errno = -flushval; // TODO map return -1; } diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index 003d7d70707fb..03b6f698db6c4 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -42,13 +42,13 @@ LLVM_LIBC_FUNCTION(int, vprintf, auto retval = printf_core::printf_main(&writer, format, args); if (retval.has_error()) { - libc_errno = retval.error; + libc_errno = retval.error; // TODO map return -1; } int flushval = wb.overflow_write(""); if (flushval != printf_core::WRITE_OK) { - libc_errno = -flushval; + libc_errno = -flushval; // TODO map return -1; } diff --git a/libc/src/stdio/generic/CMakeLists.txt b/libc/src/stdio/generic/CMakeLists.txt index 6361822b61999..77ff3b76a4d1d 100644 --- a/libc/src/stdio/generic/CMakeLists.txt +++ b/libc/src/stdio/generic/CMakeLists.txt @@ -394,6 +394,7 @@ list(APPEND fprintf_deps libc.hdr.types.FILE libc.src.__support.arg_list libc.src.stdio.printf_core.vfprintf_internal + libc.src.stdio.printf_core.core_structs ) if(LLVM_LIBC_FULL_BUILD) diff --git a/libc/src/stdio/generic/fprintf.cpp b/libc/src/stdio/generic/fprintf.cpp index 632264f944f44..e2c57809ae8cc 100644 --- a/libc/src/stdio/generic/fprintf.cpp +++ b/libc/src/stdio/generic/fprintf.cpp @@ -29,7 +29,7 @@ LLVM_LIBC_FUNCTION(int, fprintf, va_end(vlist); auto ret_val = printf_core::vfprintf_internal(stream, format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno(ret_val.error, stream); return -1; } if (ret_val.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/generic/printf.cpp b/libc/src/stdio/generic/printf.cpp index 482a65cd5a2fa..6b99433e9440a 100644 --- a/libc/src/stdio/generic/printf.cpp +++ b/libc/src/stdio/generic/printf.cpp @@ -11,6 +11,7 @@ #include "src/__support/File/file.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/vfprintf_internal.h" #include "hdr/types/FILE.h" @@ -34,7 +35,10 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { auto ret_val = printf_core::vfprintf_internal( reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno( + ret_val.error, reinterpret_cast<::FILE *>(PRINTF_STDOUT)); + return -1; + ; return -1; } if (ret_val.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/generic/vfprintf.cpp b/libc/src/stdio/generic/vfprintf.cpp index 6b39011123084..8430c99e6d84b 100644 --- a/libc/src/stdio/generic/vfprintf.cpp +++ b/libc/src/stdio/generic/vfprintf.cpp @@ -11,6 +11,7 @@ #include "src/__support/File/file.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/vfprintf_internal.h" #include "hdr/types/FILE.h" @@ -26,7 +27,7 @@ LLVM_LIBC_FUNCTION(int, vfprintf, // destruction automatically. auto ret_val = printf_core::vfprintf_internal(stream, format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno(ret_val.error, stream); return -1; } if (ret_val.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/generic/vprintf.cpp b/libc/src/stdio/generic/vprintf.cpp index 09ba2ce0d32a9..c0bde9dce9c4d 100644 --- a/libc/src/stdio/generic/vprintf.cpp +++ b/libc/src/stdio/generic/vprintf.cpp @@ -32,7 +32,8 @@ LLVM_LIBC_FUNCTION(int, vprintf, auto ret_val = printf_core::vfprintf_internal( reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno( + ret_val.error, reinterpret_cast<::FILE *>(PRINTF_STDOUT)); return -1; } if (ret_val.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt index ee66145e60156..42173e25bc5e2 100644 --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -47,6 +47,8 @@ add_header_library( libc.include.inttypes libc.src.__support.CPP.string_view libc.src.__support.FPUtil.fp_bits + libc.hdr.types.FILE + libc.src.__support.File.file ) add_header_library( diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index 3cb76ed32776f..b56eef78e02b5 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -11,9 +11,11 @@ #include "src/__support/macros/config.h" +#include "hdr/types/FILE.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/File/file.h" #include "src/stdio/printf_core/printf_config.h" #include @@ -144,6 +146,49 @@ template LIBC_INLINE constexpr TypeDesc type_desc_from_type() { // This is the value to be returned by conversions when no error has occurred. constexpr int WRITE_OK = 0; +// These are the printf return values for when an error has occurred. They are +// all negative, and should be distinct. +constexpr int FILE_WRITE_ERROR = -1; +constexpr int FILE_STATUS_ERROR = -2; +constexpr int NULLPTR_WRITE_ERROR = -3; +constexpr int INT_CONVERSION_ERROR = -4; +constexpr int FIXED_POINT_CONVERSION_ERROR = -5; +constexpr int ALLOCATION_ERROR = -6; + +LIBC_INLINE static int internal_error_to_errno(int internal_errno, + FILE *f = nullptr) { +#if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) + LIBC_NAMESPACE::File *file = reinterpret_cast(f); +#else + LIBC_NAMESPACE::File *file = nullptr; + (void)f; +#endif + + switch (-internal_errno) { + case WRITE_OK: + return 0; + case FILE_WRITE_ERROR: + if (file == nullptr) + return EIO; + return file->error_unlocked() ? file->error_code_unlocked() : EIO; + case FILE_STATUS_ERROR: + return EIO; + case NULLPTR_WRITE_ERROR: + return EINVAL; + case INT_CONVERSION_ERROR: + return ERANGE; + case FIXED_POINT_CONVERSION_ERROR: + return EINVAL; + case ALLOCATION_ERROR: + return ENOMEM; + default: + LIBC_ASSERT( + false && + "Invalid internal printf error code passed to internal_error_to_errno"); + return EINVAL; + } +} + } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/fixed_converter.h b/libc/src/stdio/printf_core/fixed_converter.h index 77384b1891174..069447f27d918 100644 --- a/libc/src/stdio/printf_core/fixed_converter.h +++ b/libc/src/stdio/printf_core/fixed_converter.h @@ -60,7 +60,7 @@ LIBC_INLINE constexpr uint32_t const_ten_exp(uint32_t exponent) { READ_FX_BITS(unsigned LENGTH_MODIFIER accum); \ } else { \ LIBC_ASSERT(false && "Invalid conversion name passed to convert_fixed"); \ - return -EINVAL; \ + return FIXED_POINT_CONVERSION_ERROR; \ } \ } while (false) diff --git a/libc/src/stdio/printf_core/int_converter.h b/libc/src/stdio/printf_core/int_converter.h index 554436c9091a8..61cb402732ab7 100644 --- a/libc/src/stdio/printf_core/int_converter.h +++ b/libc/src/stdio/printf_core/int_converter.h @@ -92,7 +92,7 @@ LIBC_INLINE int convert_int(Writer *writer, cpp::array buf; auto str = details::num_to_strview(num, buf, to_conv.conv_name); if (!str) - return -ERANGE; + return INT_CONVERSION_ERROR; size_t digits_written = str->size(); diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h index f84f60bec2fc6..b8dfb59164d33 100644 --- a/libc/src/stdio/printf_core/vasprintf_internal.h +++ b/libc/src/stdio/printf_core/vasprintf_internal.h @@ -30,7 +30,7 @@ LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) { if (new_buff == nullptr) { if (wb->buff != wb->init_buff) free(wb->buff); - return -ENOMEM; + return ALLOCATION_ERROR; } if (isBuffOnStack) inline_memcpy(new_buff, wb->buff, wb->buff_cur); @@ -59,7 +59,7 @@ LIBC_INLINE PrintfResult vasprintf_internal(char **ret, if (wb.buff == init_buff_on_stack) { *ret = static_cast(malloc(ret_val.value + 1)); if (ret == nullptr) - return {0, ENOMEM}; + return {0, ALLOCATION_ERROR}; inline_memcpy(*ret, wb.buff, ret_val.value); } else { *ret = wb.buff; diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index c50cacf2709a7..a1c2c43bd5873 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -64,7 +64,7 @@ LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) { size_t written = internal::fwrite_unlocked(new_str.data(), sizeof(char), new_str.size(), target_file); if (written != new_str.size() || internal::ferror_unlocked(target_file)) - return -EIO; + return FILE_WRITE_ERROR; return WRITE_OK; } diff --git a/libc/src/stdio/printf_core/write_int_converter.h b/libc/src/stdio/printf_core/write_int_converter.h index b424278c66185..f63a9a538690d 100644 --- a/libc/src/stdio/printf_core/write_int_converter.h +++ b/libc/src/stdio/printf_core/write_int_converter.h @@ -27,7 +27,7 @@ LIBC_INLINE int convert_write_int(Writer *writer, #ifndef LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS // This is an additional check added by LLVM-libc. if (to_conv.conv_val_ptr == nullptr) - return -EINVAL; + return NULLPTR_WRITE_ERROR; #endif // LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS size_t written = writer->get_chars_written(); diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp index 6691da1debb5a..8e42f8133c997 100644 --- a/libc/src/stdio/snprintf.cpp +++ b/libc/src/stdio/snprintf.cpp @@ -10,6 +10,7 @@ #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -34,7 +35,7 @@ LLVM_LIBC_FUNCTION(int, snprintf, auto ret_val = printf_core::printf_main(&writer, format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; } if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp index 10db9feb80121..a0935b318bd53 100644 --- a/libc/src/stdio/sprintf.cpp +++ b/libc/src/stdio/sprintf.cpp @@ -11,6 +11,7 @@ #include "src/__support/CPP/limits.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -35,7 +36,7 @@ LLVM_LIBC_FUNCTION(int, sprintf, auto ret_val = printf_core::printf_main(&writer, format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; } wb.buff[wb.buff_cur] = '\0'; diff --git a/libc/src/stdio/vasprintf.cpp b/libc/src/stdio/vasprintf.cpp index 11174727e5d64..fea49363d9079 100644 --- a/libc/src/stdio/vasprintf.cpp +++ b/libc/src/stdio/vasprintf.cpp @@ -8,6 +8,7 @@ #include "src/stdio/vasprintf.h" #include "src/__support/arg_list.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/vasprintf_internal.h" namespace LIBC_NAMESPACE_DECL { @@ -20,7 +21,7 @@ LLVM_LIBC_FUNCTION(int, vasprintf, // destruction automatically. auto ret_val = printf_core::vasprintf_internal(ret, format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; } if (ret_val.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp index 25e6165897674..466f24d3eb433 100644 --- a/libc/src/stdio/vsnprintf.cpp +++ b/libc/src/stdio/vsnprintf.cpp @@ -10,6 +10,7 @@ #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -31,7 +32,7 @@ LLVM_LIBC_FUNCTION(int, vsnprintf, auto ret_val = printf_core::printf_main(&writer, format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; } if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp index 6dda2db250d50..5a2fda6ef1a8c 100644 --- a/libc/src/stdio/vsprintf.cpp +++ b/libc/src/stdio/vsprintf.cpp @@ -11,6 +11,7 @@ #include "src/__support/CPP/limits.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -32,7 +33,7 @@ LLVM_LIBC_FUNCTION(int, vsprintf, auto ret_val = printf_core::printf_main(&writer, format, args); if (ret_val.has_error()) { - libc_errno = ret_val.error; + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; } wb.buff[wb.buff_cur] = '\0'; From d1949753dc9459f3b1c25987d670ad8e21383082 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Fri, 17 Oct 2025 06:08:42 +0000 Subject: [PATCH 18/25] Return system IO errors return values --- libc/src/__support/File/file.cpp | 58 +++++++++---------- libc/src/__support/File/file.h | 19 ++---- libc/src/stdio/generic/fprintf.cpp | 2 +- libc/src/stdio/generic/printf.cpp | 3 +- libc/src/stdio/generic/vfprintf.cpp | 2 +- libc/src/stdio/generic/vprintf.cpp | 3 +- libc/src/stdio/printf_core/core_structs.h | 33 +++++------ .../src/stdio/printf_core/vfprintf_internal.h | 28 ++++++--- 8 files changed, 73 insertions(+), 75 deletions(-) diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp index b4f0115e09bd2..4217e73828388 100644 --- a/libc/src/__support/File/file.cpp +++ b/libc/src/__support/File/file.cpp @@ -20,7 +20,7 @@ namespace LIBC_NAMESPACE_DECL { FileIOResult File::write_unlocked(const void *data, size_t len) { if (!write_allowed()) { - err_code = EBADF; + err = true; return {0, EBADF}; } @@ -45,16 +45,16 @@ FileIOResult File::write_unlocked_nbf(const uint8_t *data, size_t len) { FileIOResult write_result = platform_write(this, buf, write_size); pos = 0; // Buffer is now empty so reset pos to the beginning. // If less bytes were written than expected, then an error occurred. - if (write_result.has_error() || write_result < write_size) { - err_code = write_result.has_error() ? write_result.error : EIO; + if (write_result < write_size) { + err = true; // No bytes from data were written, so return 0. - return {0, err_code}; + return {0, write_result.error}; } } FileIOResult write_result = platform_write(this, data, len); - if (write_result.has_error() || write_result < len) - err_code = write_result.has_error() ? write_result.error : EIO; + if (write_result < len) + err = true; return write_result; } @@ -106,8 +106,9 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) { // If less bytes were written than expected, then an error occurred. Return // the number of bytes that have been written from |data|. if (buf_result.has_error() || bytes_written < write_size) { - err_code = buf_result.has_error() ? buf_result.error : EIO; - return {bytes_written <= init_pos ? 0 : bytes_written - init_pos, err_code}; + err = true; + return {bytes_written <= init_pos ? 0 : bytes_written - init_pos, + buf_result.error}; } // The second piece is handled basically the same as the first, although we @@ -127,8 +128,8 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) { // If less bytes were written than expected, then an error occurred. Return // the number of bytes that have been written from |data|. if (result.has_error() || bytes_written < remainder.size()) { - err_code = result.has_error() ? result.error : EIO; - return {primary.size() + bytes_written, err_code}; + err = true; + return {primary.size() + bytes_written, result.error}; } } @@ -165,21 +166,18 @@ FileIOResult File::write_unlocked_lbf(const uint8_t *data, size_t len) { size_t written = 0; - auto write_result = write_unlocked_nbf(primary.data(), primary.size()); - written += write_result; - if (write_result.has_error() || written < primary.size()) { - err_code = write_result.has_error() ? write_result.error : EIO; - return {written, err_code}; + written = write_unlocked_nbf(primary.data(), primary.size()); + if (written < primary.size()) { + err = true; + return written; } flush_unlocked(); - write_result = write_unlocked_fbf(remainder.data(), remainder.size()); - written += write_result; - ; - if (write_result.has_error() || written < len) { - err_code = write_result.has_error() ? write_result.error : EIO; - return {written, err_code}; + written += write_unlocked_fbf(remainder.data(), remainder.size()); + if (written < len) { + err = true; + return written; } return len; @@ -187,7 +185,7 @@ FileIOResult File::write_unlocked_lbf(const uint8_t *data, size_t len) { FileIOResult File::read_unlocked(void *data, size_t len) { if (!read_allowed()) { - err_code = EBADF; + err = true; return {0, EBADF}; } @@ -246,7 +244,7 @@ FileIOResult File::read_unlocked_fbf(uint8_t *data, size_t len) { if (!result.has_error()) eof = true; else - err_code = result.error; + err = true; return {available_data + fetched_size, result.error}; } return len; @@ -264,7 +262,7 @@ FileIOResult File::read_unlocked_fbf(uint8_t *data, size_t len) { if (!result.has_error()) eof = true; else - err_code = result.error; + err = true; } return {transfer_size + available_data, result.error}; } @@ -284,7 +282,7 @@ FileIOResult File::read_unlocked_nbf(uint8_t *data, size_t len) { if (!result.has_error()) eof = true; else - err_code = result.error; + err = true; } return {result + available_data, result.error}; } @@ -323,7 +321,7 @@ int File::ungetc_unlocked(int c) { } eof = false; // There is atleast one character that can be read now. - err_code = 0; // This operation was a success. + err = false; // This operation was a success. return c; } @@ -333,8 +331,8 @@ ErrorOr File::seek(off_t offset, int whence) { FileIOResult buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { - err_code = buf_result.has_error() ? buf_result.error : EIO; - return Error(err_code); + err = true; + return Error(buf_result.error); } } else if (prev_op == FileOp::READ && whence == SEEK_CUR) { // More data could have been read out from the platform file than was @@ -371,8 +369,8 @@ int File::flush_unlocked() { if (prev_op == FileOp::WRITE && pos > 0) { FileIOResult buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { - err_code = buf_result.has_error() ? buf_result.error : EIO; - return err_code; + err = true; + return buf_result.error; } pos = 0; } diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h index 2f7bfaf1a779a..3652e448c7f5a 100644 --- a/libc/src/__support/File/file.h +++ b/libc/src/__support/File/file.h @@ -118,7 +118,7 @@ class File { size_t read_limit; bool eof; - int err_code; + bool err; // This is a convenience RAII class to lock and unlock file objects. class FileLock { @@ -161,7 +161,7 @@ class File { /*robust=*/false, /*pshared=*/false), ungetc_buf(0), buf(buffer), bufsize(buffer_size), bufmode(buffer_mode), own_buf(owned), mode(modeflags), pos(0), prev_op(FileOp::NONE), - read_limit(0), eof(false), err_code(0) { + read_limit(0), eof(false), err(false) { adjust_buf(); } @@ -214,8 +214,8 @@ class File { if (prev_op == FileOp::WRITE && pos > 0) { auto buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { - err_code = buf_result.has_error() ? buf_result.error : EIO; - return err_code; + err = true; + return buf_result.error; } } } @@ -250,21 +250,14 @@ class File { void lock() { mutex.lock(); } void unlock() { mutex.unlock(); } - bool error_unlocked() const { return err_code != 0; } + bool error_unlocked() const { return err; } bool error() { FileLock l(this); return error_unlocked(); } - int error_code_unlocked() const { return err_code; } - - int error_code() { - FileLock l(this); - return error_code_unlocked(); - } - - void clearerr_unlocked() { err_code = 0; } + void clearerr_unlocked() { err = false; } void clearerr() { FileLock l(this); diff --git a/libc/src/stdio/generic/fprintf.cpp b/libc/src/stdio/generic/fprintf.cpp index e2c57809ae8cc..a7eb1a4e445be 100644 --- a/libc/src/stdio/generic/fprintf.cpp +++ b/libc/src/stdio/generic/fprintf.cpp @@ -29,7 +29,7 @@ LLVM_LIBC_FUNCTION(int, fprintf, va_end(vlist); auto ret_val = printf_core::vfprintf_internal(stream, format, args); if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error, stream); + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; } if (ret_val.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/generic/printf.cpp b/libc/src/stdio/generic/printf.cpp index 6b99433e9440a..9d65f435db480 100644 --- a/libc/src/stdio/generic/printf.cpp +++ b/libc/src/stdio/generic/printf.cpp @@ -35,8 +35,7 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { auto ret_val = printf_core::vfprintf_internal( reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args); if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno( - ret_val.error, reinterpret_cast<::FILE *>(PRINTF_STDOUT)); + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; ; return -1; diff --git a/libc/src/stdio/generic/vfprintf.cpp b/libc/src/stdio/generic/vfprintf.cpp index 8430c99e6d84b..0b7763e8637db 100644 --- a/libc/src/stdio/generic/vfprintf.cpp +++ b/libc/src/stdio/generic/vfprintf.cpp @@ -27,7 +27,7 @@ LLVM_LIBC_FUNCTION(int, vfprintf, // destruction automatically. auto ret_val = printf_core::vfprintf_internal(stream, format, args); if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error, stream); + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; } if (ret_val.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/generic/vprintf.cpp b/libc/src/stdio/generic/vprintf.cpp index c0bde9dce9c4d..3cf66e3fad3e2 100644 --- a/libc/src/stdio/generic/vprintf.cpp +++ b/libc/src/stdio/generic/vprintf.cpp @@ -32,8 +32,7 @@ LLVM_LIBC_FUNCTION(int, vprintf, auto ret_val = printf_core::vfprintf_internal( reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args); if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno( - ret_val.error, reinterpret_cast<::FILE *>(PRINTF_STDOUT)); + libc_errno = printf_core::internal_error_to_errno(ret_val.error); return -1; } if (ret_val.value > cpp::numeric_limits::max()) { diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index b56eef78e02b5..4348e65592160 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -148,29 +148,24 @@ template LIBC_INLINE constexpr TypeDesc type_desc_from_type() { constexpr int WRITE_OK = 0; // These are the printf return values for when an error has occurred. They are // all negative, and should be distinct. -constexpr int FILE_WRITE_ERROR = -1; -constexpr int FILE_STATUS_ERROR = -2; -constexpr int NULLPTR_WRITE_ERROR = -3; -constexpr int INT_CONVERSION_ERROR = -4; -constexpr int FIXED_POINT_CONVERSION_ERROR = -5; -constexpr int ALLOCATION_ERROR = -6; - -LIBC_INLINE static int internal_error_to_errno(int internal_errno, - FILE *f = nullptr) { -#if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) - LIBC_NAMESPACE::File *file = reinterpret_cast(f); -#else - LIBC_NAMESPACE::File *file = nullptr; - (void)f; -#endif +constexpr int FILE_WRITE_ERROR = -1001; +constexpr int FILE_STATUS_ERROR = -1002; +constexpr int NULLPTR_WRITE_ERROR = -1003; +constexpr int INT_CONVERSION_ERROR = -1004; +constexpr int FIXED_POINT_CONVERSION_ERROR = -1005; +constexpr int ALLOCATION_ERROR = -1006; +constexpr int SHORT_WRITE_ERROR = -1007; + +LIBC_INLINE static int internal_error_to_errno(int internal_errno) { + if (internal_errno < 1001) { + return internal_errno; + } switch (-internal_errno) { case WRITE_OK: return 0; case FILE_WRITE_ERROR: - if (file == nullptr) - return EIO; - return file->error_unlocked() ? file->error_code_unlocked() : EIO; + return EIO; case FILE_STATUS_ERROR: return EIO; case NULLPTR_WRITE_ERROR: @@ -181,6 +176,8 @@ LIBC_INLINE static int internal_error_to_errno(int internal_errno, return EINVAL; case ALLOCATION_ERROR: return ENOMEM; + case SHORT_WRITE_ERROR: + return EIO; default: LIBC_ASSERT( false && diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index a1c2c43bd5873..2428508d0178c 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -36,8 +36,8 @@ LIBC_INLINE void funlockfile(FILE *f) { reinterpret_cast(f)->unlock(); } -LIBC_INLINE size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, - FILE *f) { +LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size, + size_t nmemb, FILE *f) { return reinterpret_cast(f)->write_unlocked( ptr, size * nmemb); } @@ -48,9 +48,9 @@ LIBC_INLINE void flockfile(::FILE *f) { ::flockfile(f); } LIBC_INLINE void funlockfile(::FILE *f) { ::funlockfile(f); } -LIBC_INLINE size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, - ::FILE *f) { - return ::fwrite_unlocked(ptr, size, nmemb, f); +LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size, + size_t nmemb, ::FILE *f) { + return {::fwrite_unlocked(ptr, size, nmemb, f), 0}; // todo err } #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace internal @@ -61,10 +61,22 @@ LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) { ::FILE *target_file = reinterpret_cast<::FILE *>(fp); // Write new_str to the target file. The logic preventing a zero-length write // is in the writer, so we don't check here. - size_t written = internal::fwrite_unlocked(new_str.data(), sizeof(char), - new_str.size(), target_file); - if (written != new_str.size() || internal::ferror_unlocked(target_file)) + auto write_result = internal::fwrite_unlocked(new_str.data(), sizeof(char), + new_str.size(), target_file); + // Propagate actual system error in FileIOResult. + if (write_result.has_error()) + return -write_result.error; + + // On short write no system error is returned, so return custom error. + if (write_result.value != new_str.size()) + return SHORT_WRITE_ERROR; + + // Return custom error in case error wasn't set on FileIOResult for some + // reason (like using LIBC_COPT_STDIO_USE_SYSTEM_FILE) + if (internal::ferror_unlocked(target_file)) { return FILE_WRITE_ERROR; + } + return WRITE_OK; } From 69e93624cfe0707649a6c15cdaa3c883bad73417 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Fri, 17 Oct 2025 06:29:21 +0000 Subject: [PATCH 19/25] Use ErroOr for print retval instead of custom struct --- libc/src/stdio/asprintf.cpp | 8 ++++---- libc/src/stdio/baremetal/printf.cpp | 8 ++++---- libc/src/stdio/baremetal/vprintf.cpp | 8 ++++---- libc/src/stdio/generic/fprintf.cpp | 8 ++++---- libc/src/stdio/generic/printf.cpp | 10 ++++------ libc/src/stdio/generic/vfprintf.cpp | 8 ++++---- libc/src/stdio/generic/vprintf.cpp | 8 ++++---- libc/src/stdio/printf_core/CMakeLists.txt | 3 +++ libc/src/stdio/printf_core/core_structs.h | 12 ------------ libc/src/stdio/printf_core/printf_main.h | 8 +++++--- libc/src/stdio/printf_core/vasprintf_internal.h | 17 +++++++++-------- libc/src/stdio/printf_core/vfprintf_internal.h | 11 ++++++----- libc/src/stdio/snprintf.cpp | 8 ++++---- libc/src/stdio/sprintf.cpp | 8 ++++---- libc/src/stdio/vasprintf.cpp | 8 ++++---- libc/src/stdio/vsnprintf.cpp | 8 ++++---- libc/src/stdio/vsprintf.cpp | 8 ++++---- 17 files changed, 71 insertions(+), 78 deletions(-) diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp index 014cf7efade6b..3187ea40490a4 100644 --- a/libc/src/stdio/asprintf.cpp +++ b/libc/src/stdio/asprintf.cpp @@ -23,16 +23,16 @@ LLVM_LIBC_FUNCTION(int, asprintf, // destruction automatically. va_end(vlist); auto ret_val = printf_core::vasprintf_internal(buffer, format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index 5ac9433152ee9..53a7c95219664 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -43,8 +43,8 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { printf_core::Writer writer(wb); auto retval = printf_core::printf_main(&writer, format, args); - if (retval.has_error()) { - libc_errno = retval.error; // TODO map + if (!retval.has_value()) { + libc_errno = retval.error(); // TODO map return -1; } @@ -54,12 +54,12 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { return -1; } - if (retval.value > cpp::numeric_limits::max()) { + if (retval.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(retval.value); + return static_cast(retval.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index 03b6f698db6c4..2a058885a0d9b 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -41,8 +41,8 @@ LLVM_LIBC_FUNCTION(int, vprintf, printf_core::Writer writer(wb); auto retval = printf_core::printf_main(&writer, format, args); - if (retval.has_error()) { - libc_errno = retval.error; // TODO map + if (!retval.has_value()) { + libc_errno = retval.error(); // TODO map return -1; } @@ -52,12 +52,12 @@ LLVM_LIBC_FUNCTION(int, vprintf, return -1; } - if (retval.value > cpp::numeric_limits::max()) { + if (retval.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(retval.value); + return static_cast(retval.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/fprintf.cpp b/libc/src/stdio/generic/fprintf.cpp index a7eb1a4e445be..8251a098a9705 100644 --- a/libc/src/stdio/generic/fprintf.cpp +++ b/libc/src/stdio/generic/fprintf.cpp @@ -28,16 +28,16 @@ LLVM_LIBC_FUNCTION(int, fprintf, // destruction automatically. va_end(vlist); auto ret_val = printf_core::vfprintf_internal(stream, format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/printf.cpp b/libc/src/stdio/generic/printf.cpp index 9d65f435db480..2ff1b35c02c07 100644 --- a/libc/src/stdio/generic/printf.cpp +++ b/libc/src/stdio/generic/printf.cpp @@ -34,18 +34,16 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { va_end(vlist); auto ret_val = printf_core::vfprintf_internal( reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); - return -1; - ; + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/vfprintf.cpp b/libc/src/stdio/generic/vfprintf.cpp index 0b7763e8637db..280f8092a5520 100644 --- a/libc/src/stdio/generic/vfprintf.cpp +++ b/libc/src/stdio/generic/vfprintf.cpp @@ -26,16 +26,16 @@ LLVM_LIBC_FUNCTION(int, vfprintf, // and pointer semantics, as well as handling // destruction automatically. auto ret_val = printf_core::vfprintf_internal(stream, format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/vprintf.cpp b/libc/src/stdio/generic/vprintf.cpp index 3cf66e3fad3e2..ba9b283bf9655 100644 --- a/libc/src/stdio/generic/vprintf.cpp +++ b/libc/src/stdio/generic/vprintf.cpp @@ -31,16 +31,16 @@ LLVM_LIBC_FUNCTION(int, vprintf, // destruction automatically. auto ret_val = printf_core::vfprintf_internal( reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt index 42173e25bc5e2..95c32f4ac16b7 100644 --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -127,6 +127,7 @@ add_header_library( .writer .core_structs libc.src.__support.arg_list + libc.src.__support.error_or ) add_header_library( @@ -138,6 +139,7 @@ add_header_library( libc.hdr.func.free libc.hdr.func.realloc libc.src.__support.arg_list + libc.src.__support.error_or libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer ) @@ -154,6 +156,7 @@ add_header_library( vfprintf_internal.h DEPENDS libc.src.__support.File.file + libc.src.__support.error_or libc.src.__support.arg_list libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index 4348e65592160..726b767778848 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -24,18 +24,6 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { -struct PrintfResult { - size_t value; - int error; - - constexpr PrintfResult(size_t val) : value(val), error(0) {} - constexpr PrintfResult(size_t val, int error) : value(val), error(error) {} - - constexpr bool has_error() { return error != 0; } - - constexpr operator size_t() { return value; } -}; - // These length modifiers match the length modifiers in the format string, which // is why they are formatted differently from the rest of the file. enum class LengthModifier { hh, h, l, ll, j, z, t, L, w, wf, none }; diff --git a/libc/src/stdio/printf_core/printf_main.h b/libc/src/stdio/printf_core/printf_main.h index f187b43a9cd8f..1c7a7237c097d 100644 --- a/libc/src/stdio/printf_core/printf_main.h +++ b/libc/src/stdio/printf_core/printf_main.h @@ -10,6 +10,7 @@ #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PRINTF_MAIN_H #include "src/__support/arg_list.h" +#include "src/__support/error_or.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/converter.h" #include "src/stdio/printf_core/core_structs.h" @@ -22,8 +23,9 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { template -PrintfResult printf_main(Writer *writer, const char *__restrict str, - internal::ArgList &args) { +ErrorOr printf_main(Writer *writer, + const char *__restrict str, + internal::ArgList &args) { Parser parser(str, args); int result = 0; for (FormatSection cur_section = parser.get_next_section(); @@ -34,7 +36,7 @@ PrintfResult printf_main(Writer *writer, const char *__restrict str, else result = writer->write(cur_section.raw_string); if (result < 0) - return {0, -result}; + return Error(-result); } return writer->get_chars_written(); diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h index b8dfb59164d33..50ebf0ea4555d 100644 --- a/libc/src/stdio/printf_core/vasprintf_internal.h +++ b/libc/src/stdio/printf_core/vasprintf_internal.h @@ -11,6 +11,7 @@ #include "hdr/func/malloc.h" #include "hdr/func/realloc.h" #include "src/__support/arg_list.h" +#include "src/__support/error_or.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -43,28 +44,28 @@ LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) { constexpr size_t DEFAULT_BUFFER_SIZE = 200; -LIBC_INLINE PrintfResult vasprintf_internal(char **ret, - const char *__restrict format, - internal::ArgList args) { +LIBC_INLINE ErrorOr vasprintf_internal(char **ret, + const char *__restrict format, + internal::ArgList args) { char init_buff_on_stack[DEFAULT_BUFFER_SIZE]; printf_core::WriteBuffer::value> wb( init_buff_on_stack, DEFAULT_BUFFER_SIZE, resize_overflow_hook); printf_core::Writer writer(wb); auto ret_val = printf_core::printf_main(&writer, format, args); - if (ret_val.has_error()) { + if (!ret_val.has_value()) { *ret = nullptr; return ret_val; } if (wb.buff == init_buff_on_stack) { - *ret = static_cast(malloc(ret_val.value + 1)); + *ret = static_cast(malloc(ret_val.value() + 1)); if (ret == nullptr) - return {0, ALLOCATION_ERROR}; - inline_memcpy(*ret, wb.buff, ret_val.value); + return Error(ALLOCATION_ERROR); + inline_memcpy(*ret, wb.buff, ret_val.value()); } else { *ret = wb.buff; } - (*ret)[ret_val.value] = '\0'; + (*ret)[ret_val.value()] = '\0'; return ret_val; } } // namespace printf_core diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index 2428508d0178c..3fabe04d921cc 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -12,6 +12,7 @@ #include "hdr/errno_macros.h" #include "src/__support/File/file.h" #include "src/__support/arg_list.h" +#include "src/__support/error_or.h" #include "src/__support/macros/attributes.h" // For LIBC_INLINE #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" @@ -80,9 +81,9 @@ LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) { return WRITE_OK; } -LIBC_INLINE PrintfResult vfprintf_internal(::FILE *__restrict stream, - const char *__restrict format, - internal::ArgList &args) { +LIBC_INLINE ErrorOr vfprintf_internal(::FILE *__restrict stream, + const char *__restrict format, + internal::ArgList &args) { constexpr size_t BUFF_SIZE = 1024; char buffer[BUFF_SIZE]; printf_core::WriteBuffer::value> wb( @@ -90,13 +91,13 @@ LIBC_INLINE PrintfResult vfprintf_internal(::FILE *__restrict stream, Writer writer(wb); internal::flockfile(stream); auto retval = printf_main(&writer, format, args); - if (retval.has_error()) { + if (!retval.has_value()) { internal::funlockfile(stream); return retval; } int flushval = wb.overflow_write(""); if (flushval != WRITE_OK) - retval.error = -flushval; + retval = Error(-flushval); internal::funlockfile(stream); return retval; } diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp index 8e42f8133c997..d63f5c8f0957e 100644 --- a/libc/src/stdio/snprintf.cpp +++ b/libc/src/stdio/snprintf.cpp @@ -34,19 +34,19 @@ LLVM_LIBC_FUNCTION(int, snprintf, printf_core::Writer writer(wb); auto ret_val = printf_core::printf_main(&writer, format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. wb.buff[wb.buff_cur] = '\0'; - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp index a0935b318bd53..b9be409500086 100644 --- a/libc/src/stdio/sprintf.cpp +++ b/libc/src/stdio/sprintf.cpp @@ -35,18 +35,18 @@ LLVM_LIBC_FUNCTION(int, sprintf, printf_core::Writer writer(wb); auto ret_val = printf_core::printf_main(&writer, format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } wb.buff[wb.buff_cur] = '\0'; - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vasprintf.cpp b/libc/src/stdio/vasprintf.cpp index fea49363d9079..4e3e601e12b94 100644 --- a/libc/src/stdio/vasprintf.cpp +++ b/libc/src/stdio/vasprintf.cpp @@ -20,15 +20,15 @@ LLVM_LIBC_FUNCTION(int, vasprintf, // and pointer semantics, as well as handling // destruction automatically. auto ret_val = printf_core::vasprintf_internal(ret, format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp index 466f24d3eb433..d822a1090f647 100644 --- a/libc/src/stdio/vsnprintf.cpp +++ b/libc/src/stdio/vsnprintf.cpp @@ -31,19 +31,19 @@ LLVM_LIBC_FUNCTION(int, vsnprintf, printf_core::Writer writer(wb); auto ret_val = printf_core::printf_main(&writer, format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. wb.buff[wb.buff_cur] = '\0'; - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp index 5a2fda6ef1a8c..dd03c71f114a8 100644 --- a/libc/src/stdio/vsprintf.cpp +++ b/libc/src/stdio/vsprintf.cpp @@ -32,17 +32,17 @@ LLVM_LIBC_FUNCTION(int, vsprintf, printf_core::Writer writer(wb); auto ret_val = printf_core::printf_main(&writer, format, args); - if (ret_val.has_error()) { - libc_errno = printf_core::internal_error_to_errno(ret_val.error); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; } wb.buff[wb.buff_cur] = '\0'; - if (ret_val.value > cpp::numeric_limits::max()) { + if (ret_val.value() > cpp::numeric_limits::max()) { libc_errno = EOVERFLOW; return -1; } - return static_cast(ret_val.value); + return static_cast(ret_val.value()); } } // namespace LIBC_NAMESPACE_DECL From f8cb7022e9175678da0966758b65c30733d2997b Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Fri, 17 Oct 2025 14:28:57 +0000 Subject: [PATCH 20/25] Fix tests --- libc/src/stdio/printf_core/core_structs.h | 18 +++++++++--------- libc/src/stdio/printf_core/vfprintf_internal.h | 14 +++++--------- libc/test/src/stdio/CMakeLists.txt | 6 +++++- libc/test/src/stdio/fprintf_test.cpp | 16 +++++++++++----- libc/test/src/stdio/vfprintf_test.cpp | 16 +++++++++++----- 5 files changed, 41 insertions(+), 29 deletions(-) diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index 726b767778848..e088bddd4db3f 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -134,22 +134,24 @@ template LIBC_INLINE constexpr TypeDesc type_desc_from_type() { // This is the value to be returned by conversions when no error has occurred. constexpr int WRITE_OK = 0; -// These are the printf return values for when an error has occurred. They are -// all negative, and should be distinct. +// These are the error return values used by the printf engine when an +// error has occurred. They are all large negative, distinct values starting +// from -1000 to not overlap with system errors. constexpr int FILE_WRITE_ERROR = -1001; constexpr int FILE_STATUS_ERROR = -1002; constexpr int NULLPTR_WRITE_ERROR = -1003; constexpr int INT_CONVERSION_ERROR = -1004; constexpr int FIXED_POINT_CONVERSION_ERROR = -1005; constexpr int ALLOCATION_ERROR = -1006; -constexpr int SHORT_WRITE_ERROR = -1007; -LIBC_INLINE static int internal_error_to_errno(int internal_errno) { - if (internal_errno < 1001) { - return internal_errno; +LIBC_INLINE static int internal_error_to_errno(int internal_error) { + // System error occured, return error as is. + if (internal_error < 1001) { + return internal_error; } - switch (-internal_errno) { + // Map internal error to errno. + switch (-internal_error) { case WRITE_OK: return 0; case FILE_WRITE_ERROR: @@ -164,8 +166,6 @@ LIBC_INLINE static int internal_error_to_errno(int internal_errno) { return EINVAL; case ALLOCATION_ERROR: return ENOMEM; - case SHORT_WRITE_ERROR: - return EIO; default: LIBC_ASSERT( false && diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index 3fabe04d921cc..6e29c6a6a3695 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -51,7 +51,7 @@ LIBC_INLINE void funlockfile(::FILE *f) { ::funlockfile(f); } LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, ::FILE *f) { - return {::fwrite_unlocked(ptr, size, nmemb, f), 0}; // todo err + return {::fwrite_unlocked(ptr, size, nmemb, f), errno}; } #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace internal @@ -68,15 +68,11 @@ LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) { if (write_result.has_error()) return -write_result.error; - // On short write no system error is returned, so return custom error. - if (write_result.value != new_str.size()) - return SHORT_WRITE_ERROR; - - // Return custom error in case error wasn't set on FileIOResult for some - // reason (like using LIBC_COPT_STDIO_USE_SYSTEM_FILE) - if (internal::ferror_unlocked(target_file)) { + // In case short write occured or error was not set on FileIOResult for some + // reason. + if (write_result.value != new_str.size() || + internal::ferror_unlocked(target_file)) return FILE_WRITE_ERROR; - } return WRITE_OK; } diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt index b513007cdf7c6..abf67f4e97afc 100644 --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -169,8 +169,12 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdio.ferror libc.src.stdio.fopen libc.src.stdio.fread - libc.src.stdio.fopencookie ) + if(${LIBC_TARGET_OS} STREQUAL "linux") + list(APPEND fprintf_test_deps + libc.src.stdio.fopencookie + ) + endif() # This is to be used for tests which write to libc's platform streams # under full build but write to system-lib's streams otherwise. set(hermetic_test_only HERMETIC_TEST_ONLY) diff --git a/libc/test/src/stdio/fprintf_test.cpp b/libc/test/src/stdio/fprintf_test.cpp index 9a26c44e7f12c..186e090fe9181 100644 --- a/libc/test/src/stdio/fprintf_test.cpp +++ b/libc/test/src/stdio/fprintf_test.cpp @@ -10,7 +10,6 @@ #include "src/stdio/fclose.h" #include "src/stdio/ferror.h" #include "src/stdio/fopen.h" -#include "src/stdio/fopencookie.h" #include "src/stdio/fread.h" #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE @@ -21,18 +20,21 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#if defined(LIBC_TARGET_OS_IS_LINUX) && \ + !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) +#include "src/stdio/fopencookie.h" +#endif + namespace printf_test { #ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE using LIBC_NAMESPACE::fclose; using LIBC_NAMESPACE::ferror; using LIBC_NAMESPACE::fopen; -using LIBC_NAMESPACE::fopencookie; using LIBC_NAMESPACE::fread; #else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) using ::fclose; using ::ferror; using ::fopen; -using ::fopencookie; using ::fread; #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace printf_test @@ -86,11 +88,13 @@ TEST(LlvmLibcFPrintfTest, WriteToFile) { written = LIBC_NAMESPACE::fprintf(file, "Writing to a read only file should fail."); EXPECT_LT(written, 0); - ASSERT_ERRNO_EQ(EIO); + ASSERT_ERRNO_EQ(EBADF); ASSERT_EQ(printf_test::fclose(file), 0); } +#if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && \ + defined(LIBC_TARGET_OS_IS_LINUX) TEST(LlvmLibcFPrintfTest, CharsWrittenOverflow) { struct NoopStream {}; auto noop_write = [](void *, const char *, size_t size) -> ssize_t { @@ -99,7 +103,7 @@ TEST(LlvmLibcFPrintfTest, CharsWrittenOverflow) { NoopStream stream; cookie_io_functions_t funcs = {nullptr, +noop_write, nullptr, nullptr}; - ::FILE *file = printf_test::fopencookie(&stream, "w", funcs); + ::FILE *file = LIBC_NAMESPACE::fopencookie(&stream, "w", funcs); ASSERT_NE(file, nullptr); // Trigger an overflow in the return value of fprintf by writing more than @@ -113,6 +117,8 @@ TEST(LlvmLibcFPrintfTest, CharsWrittenOverflow) { EXPECT_EQ(printf_test::fclose(file), 0); } +#endif // #if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && + // defined(LIBC_TARGET_OS_IS_LINUX) #ifndef LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS TEST(LlvmLibcFPrintfTest, NullPtrCheck) { diff --git a/libc/test/src/stdio/vfprintf_test.cpp b/libc/test/src/stdio/vfprintf_test.cpp index 952c55b0b0a85..8340bf90b30a8 100644 --- a/libc/test/src/stdio/vfprintf_test.cpp +++ b/libc/test/src/stdio/vfprintf_test.cpp @@ -14,7 +14,6 @@ #include "src/stdio/fclose.h" #include "src/stdio/ferror.h" #include "src/stdio/fopen.h" -#include "src/stdio/fopencookie.h" #include "src/stdio/fread.h" #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE @@ -24,18 +23,21 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#if defined(LIBC_TARGET_OS_IS_LINUX) && \ + !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) +#include "src/stdio/fopencookie.h" +#endif + namespace printf_test { #ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE using LIBC_NAMESPACE::fclose; using LIBC_NAMESPACE::ferror; using LIBC_NAMESPACE::fopen; -using LIBC_NAMESPACE::fopencookie; using LIBC_NAMESPACE::fread; #else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) using ::fclose; using ::ferror; using ::fopen; -using ::fopencookie; using ::fread; #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE } // namespace printf_test @@ -97,11 +99,13 @@ TEST(LlvmLibcVFPrintfTest, WriteToFile) { written = call_vfprintf(file, "Writing to a read only file should fail."); EXPECT_LT(written, 0); - ASSERT_ERRNO_EQ(EIO); + ASSERT_ERRNO_EQ(EBADF); ASSERT_EQ(printf_test::fclose(file), 0); } +#if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && \ + defined(LIBC_TARGET_OS_IS_LINUX) TEST(LlvmLibcVFPrintfTest, CharsWrittenOverflow) { struct NoopStream {}; auto noop_write = [](void *, const char *, size_t size) -> ssize_t { @@ -110,7 +114,7 @@ TEST(LlvmLibcVFPrintfTest, CharsWrittenOverflow) { NoopStream stream; cookie_io_functions_t funcs = {nullptr, +noop_write, nullptr, nullptr}; - ::FILE *file = printf_test::fopencookie(&stream, "w", funcs); + ::FILE *file = LIBC_NAMESPACE::fopencookie(&stream, "w", funcs); ASSERT_NE(file, nullptr); // Trigger an overflow in the return value of vfprintf by writing more than @@ -124,3 +128,5 @@ TEST(LlvmLibcVFPrintfTest, CharsWrittenOverflow) { EXPECT_EQ(printf_test::fclose(file), 0); } +#endif // !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && + // defined(LIBC_TARGET_OS_IS_LINUX) From 0e8b25c861a63a9e6a359c49c404ec54757494da Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Fri, 17 Oct 2025 17:28:58 +0000 Subject: [PATCH 21/25] Fix baremetal impl --- .../llvm-libc-macros/generic-error-number-macros.h | 1 + libc/src/stdio/CMakeLists.txt | 10 ++++++++++ libc/src/stdio/asprintf.cpp | 2 ++ libc/src/stdio/baremetal/CMakeLists.txt | 2 ++ libc/src/stdio/baremetal/printf.cpp | 5 +++-- libc/src/stdio/baremetal/vprintf.cpp | 6 ++++-- libc/src/stdio/printf_core/CMakeLists.txt | 1 + libc/src/stdio/printf_core/core_structs.h | 1 + libc/src/stdio/snprintf.cpp | 2 ++ libc/src/stdio/sprintf.cpp | 2 ++ libc/src/stdio/vasprintf.cpp | 2 ++ libc/src/stdio/vsnprintf.cpp | 2 ++ libc/src/stdio/vsprintf.cpp | 2 ++ libc/src/time/strftime_core/strftime_main.h | 2 +- 14 files changed, 35 insertions(+), 5 deletions(-) diff --git a/libc/include/llvm-libc-macros/generic-error-number-macros.h b/libc/include/llvm-libc-macros/generic-error-number-macros.h index 199a86217b347..5dd6eb2f97051 100644 --- a/libc/include/llvm-libc-macros/generic-error-number-macros.h +++ b/libc/include/llvm-libc-macros/generic-error-number-macros.h @@ -43,6 +43,7 @@ #define EPIPE 32 #define EDOM 33 #define ERANGE 34 +#define EOVERFLOW 75 #define EILSEQ 84 #endif // LLVM_LIBC_MACROS_GENERIC_ERROR_NUMBER_MACROS_H diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt index d7af6c47efbc8..72fda8d343815 100644 --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -126,6 +126,8 @@ add_entrypoint_object( libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer libc.src.stdio.printf_core.core_structs + libc.src.__support.libc_errno + libc.hdr.errno_macros ) add_entrypoint_object( @@ -138,6 +140,8 @@ add_entrypoint_object( libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer libc.src.stdio.printf_core.core_structs + libc.src.__support.libc_errno + libc.hdr.errno_macros ) add_entrypoint_object( @@ -149,6 +153,8 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.vasprintf_internal libc.src.stdio.printf_core.core_structs + libc.src.__support.libc_errno + libc.hdr.errno_macros ) add_entrypoint_object( @@ -173,6 +179,8 @@ add_entrypoint_object( libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer libc.src.stdio.printf_core.core_structs + libc.src.__support.libc_errno + libc.hdr.errno_macros ) add_entrypoint_object( @@ -184,6 +192,8 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.vasprintf_internal libc.src.stdio.printf_core.core_structs + libc.src.__support.libc_errno + libc.hdr.errno_macros ) add_subdirectory(printf_core) diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp index 3187ea40490a4..bb4077fa89542 100644 --- a/libc/src/stdio/asprintf.cpp +++ b/libc/src/stdio/asprintf.cpp @@ -7,7 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/stdio/asprintf.h" +#include "hdr/errno_macros.h" #include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/vasprintf_internal.h" diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt index 548938f885c94..e4de151b109ed 100644 --- a/libc/src/stdio/baremetal/CMakeLists.txt +++ b/libc/src/stdio/baremetal/CMakeLists.txt @@ -31,6 +31,7 @@ add_entrypoint_object( libc.src.stdio.printf_core.writer libc.src.__support.arg_list libc.src.__support.OSUtil.osutil + libc.src.__support.libc_errno ) add_entrypoint_object( @@ -89,6 +90,7 @@ add_entrypoint_object( libc.src.stdio.printf_core.writer libc.src.__support.arg_list libc.src.__support.OSUtil.osutil + libc.src.__support.libc_errno ) add_entrypoint_object( diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index 53a7c95219664..7ce2bb5e256cb 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -9,6 +9,7 @@ #include "src/stdio/printf.h" #include "src/__support/OSUtil/io.h" #include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" @@ -44,13 +45,13 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { auto retval = printf_core::printf_main(&writer, format, args); if (!retval.has_value()) { - libc_errno = retval.error(); // TODO map + libc_errno = printf_core::internal_error_to_errno(retval.error()); return -1; } int flushval = wb.overflow_write(""); if (flushval != printf_core::WRITE_OK) { - libc_errno = -flushval; // TODO map + libc_errno = printf_core::internal_error_to_errno(-flushval); return -1; } diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index 2a058885a0d9b..e60260c49138d 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -7,8 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/stdio/vprintf.h" +#include "hdr/errno_macros.h" #include "src/__support/OSUtil/io.h" #include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" @@ -42,13 +44,13 @@ LLVM_LIBC_FUNCTION(int, vprintf, auto retval = printf_core::printf_main(&writer, format, args); if (!retval.has_value()) { - libc_errno = retval.error(); // TODO map + libc_errno = printf_core::internal_error_to_errno(retval.error()); return -1; } int flushval = wb.overflow_write(""); if (flushval != printf_core::WRITE_OK) { - libc_errno = -flushval; // TODO map + libc_errno = printf_core::internal_error_to_errno(-flushval); return -1; } diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt index 95c32f4ac16b7..24435c3a03d63 100644 --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -48,6 +48,7 @@ add_header_library( libc.src.__support.CPP.string_view libc.src.__support.FPUtil.fp_bits libc.hdr.types.FILE + libc.hdr.errno_macros libc.src.__support.File.file ) diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index e088bddd4db3f..37c11e28ce7ea 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -11,6 +11,7 @@ #include "src/__support/macros/config.h" +#include "hdr/errno_macros.h" #include "hdr/types/FILE.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/type_traits.h" diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp index d63f5c8f0957e..10b46ddfd6249 100644 --- a/libc/src/stdio/snprintf.cpp +++ b/libc/src/stdio/snprintf.cpp @@ -8,7 +8,9 @@ #include "src/stdio/snprintf.h" +#include "hdr/errno_macros.h" #include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp index b9be409500086..53e951bea6aaa 100644 --- a/libc/src/stdio/sprintf.cpp +++ b/libc/src/stdio/sprintf.cpp @@ -8,8 +8,10 @@ #include "src/stdio/sprintf.h" +#include "hdr/errno_macros.h" #include "src/__support/CPP/limits.h" #include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" diff --git a/libc/src/stdio/vasprintf.cpp b/libc/src/stdio/vasprintf.cpp index 4e3e601e12b94..1060c39d416c1 100644 --- a/libc/src/stdio/vasprintf.cpp +++ b/libc/src/stdio/vasprintf.cpp @@ -7,7 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/stdio/vasprintf.h" +#include "hdr/errno_macros.h" #include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/vasprintf_internal.h" diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp index d822a1090f647..000ec5d5cfa5b 100644 --- a/libc/src/stdio/vsnprintf.cpp +++ b/libc/src/stdio/vsnprintf.cpp @@ -8,7 +8,9 @@ #include "src/stdio/vsnprintf.h" +#include "hdr/errno_macros.h" #include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp index dd03c71f114a8..5f8c79418e83d 100644 --- a/libc/src/stdio/vsprintf.cpp +++ b/libc/src/stdio/vsprintf.cpp @@ -8,8 +8,10 @@ #include "src/stdio/vsprintf.h" +#include "hdr/errno_macros.h" #include "src/__support/CPP/limits.h" #include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_main.h" diff --git a/libc/src/time/strftime_core/strftime_main.h b/libc/src/time/strftime_core/strftime_main.h index 8e369c2710ddb..2b136d83234cd 100644 --- a/libc/src/time/strftime_core/strftime_main.h +++ b/libc/src/time/strftime_core/strftime_main.h @@ -36,7 +36,7 @@ int strftime_main(printf_core::Writer *writer, return result; } - // TODO: return result struct like printf, so that size_t can be returned + // TODO: Use ErrorOr return static_cast(writer->get_chars_written()); } From 756cb37f38a698ca66e17a51546108a8081b054a Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Sat, 18 Oct 2025 06:26:12 +0000 Subject: [PATCH 22/25] Clean up tests, dependencies --- libc/src/stdio/printf_core/CMakeLists.txt | 2 -- libc/src/stdio/printf_core/core_structs.h | 2 -- libc/src/stdio/printf_core/fixed_converter.h | 1 - .../src/stdio/printf_core/vfprintf_internal.h | 1 - libc/test/src/stdio/CMakeLists.txt | 5 --- libc/test/src/stdio/fprintf_test.cpp | 32 ------------------- libc/test/src/stdio/snprintf_test.cpp | 15 +++++++++ libc/test/src/stdio/vfprintf_test.cpp | 32 ------------------- 8 files changed, 15 insertions(+), 75 deletions(-) diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt index 24435c3a03d63..dbb36ac96bc4c 100644 --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -47,9 +47,7 @@ add_header_library( libc.include.inttypes libc.src.__support.CPP.string_view libc.src.__support.FPUtil.fp_bits - libc.hdr.types.FILE libc.hdr.errno_macros - libc.src.__support.File.file ) add_header_library( diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index 37c11e28ce7ea..7b205ee890c98 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -12,11 +12,9 @@ #include "src/__support/macros/config.h" #include "hdr/errno_macros.h" -#include "hdr/types/FILE.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/__support/File/file.h" #include "src/stdio/printf_core/printf_config.h" #include diff --git a/libc/src/stdio/printf_core/fixed_converter.h b/libc/src/stdio/printf_core/fixed_converter.h index 069447f27d918..e8a3314967562 100644 --- a/libc/src/stdio/printf_core/fixed_converter.h +++ b/libc/src/stdio/printf_core/fixed_converter.h @@ -9,7 +9,6 @@ #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FIXED_CONVERTER_H #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FIXED_CONVERTER_H -#include "hdr/errno_macros.h" #include "include/llvm-libc-macros/stdfix-macros.h" #include "src/__support/CPP/string_view.h" #include "src/__support/ctype_utils.h" diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index 6e29c6a6a3695..4e60248810f27 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -9,7 +9,6 @@ #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_VFPRINTF_INTERNAL_H #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_VFPRINTF_INTERNAL_H -#include "hdr/errno_macros.h" #include "src/__support/File/file.h" #include "src/__support/arg_list.h" #include "src/__support/error_or.h" diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt index abf67f4e97afc..d71f1dff11943 100644 --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -170,11 +170,6 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdio.fopen libc.src.stdio.fread ) - if(${LIBC_TARGET_OS} STREQUAL "linux") - list(APPEND fprintf_test_deps - libc.src.stdio.fopencookie - ) - endif() # This is to be used for tests which write to libc's platform streams # under full build but write to system-lib's streams otherwise. set(hermetic_test_only HERMETIC_TEST_ONLY) diff --git a/libc/test/src/stdio/fprintf_test.cpp b/libc/test/src/stdio/fprintf_test.cpp index 186e090fe9181..1d081f00a31a4 100644 --- a/libc/test/src/stdio/fprintf_test.cpp +++ b/libc/test/src/stdio/fprintf_test.cpp @@ -20,11 +20,6 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#if defined(LIBC_TARGET_OS_IS_LINUX) && \ - !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) -#include "src/stdio/fopencookie.h" -#endif - namespace printf_test { #ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE using LIBC_NAMESPACE::fclose; @@ -93,33 +88,6 @@ TEST(LlvmLibcFPrintfTest, WriteToFile) { ASSERT_EQ(printf_test::fclose(file), 0); } -#if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && \ - defined(LIBC_TARGET_OS_IS_LINUX) -TEST(LlvmLibcFPrintfTest, CharsWrittenOverflow) { - struct NoopStream {}; - auto noop_write = [](void *, const char *, size_t size) -> ssize_t { - return size; - }; - - NoopStream stream; - cookie_io_functions_t funcs = {nullptr, +noop_write, nullptr, nullptr}; - ::FILE *file = LIBC_NAMESPACE::fopencookie(&stream, "w", funcs); - ASSERT_NE(file, nullptr); - - // Trigger an overflow in the return value of fprintf by writing more than - // INT_MAX bytes. We do this by printing a string with precision INT_MAX, and - // then one more character. - int max_int = LIBC_NAMESPACE::cpp::numeric_limits::max(); - int result = LIBC_NAMESPACE::fprintf(file, "%*sA", max_int, ""); - - EXPECT_LT(result, 0); - ASSERT_ERRNO_EQ(EOVERFLOW); - - EXPECT_EQ(printf_test::fclose(file), 0); -} -#endif // #if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && - // defined(LIBC_TARGET_OS_IS_LINUX) - #ifndef LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS TEST(LlvmLibcFPrintfTest, NullPtrCheck) { const char *FILENAME = APPEND_LIBC_TEST("fprintf_nullptr.test"); diff --git a/libc/test/src/stdio/snprintf_test.cpp b/libc/test/src/stdio/snprintf_test.cpp index baaa664cdc9ee..1062f952d7429 100644 --- a/libc/test/src/stdio/snprintf_test.cpp +++ b/libc/test/src/stdio/snprintf_test.cpp @@ -8,8 +8,12 @@ #include "src/stdio/snprintf.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +using LlvmLibcSNPrintfTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + // The sprintf test cases cover testing the shared printf functionality, so // these tests will focus on snprintf exclusive features. @@ -59,3 +63,14 @@ TEST(LlvmLibcSNPrintfTest, NoCutOff) { EXPECT_EQ(written, 10); ASSERT_STREQ(buff, "1234567890"); } + +TEST(LlvmLibcSNPrintfTest, CharsWrittenOverflow) { + char buff[0]; + + // Trigger an overflow in the return value of snprintf by writing more than + // INT_MAX bytes. + int int_max = LIBC_NAMESPACE::cpp::numeric_limits::max(); + int written = LIBC_NAMESPACE::snprintf(buff, 0, "%*stest", int_max, ""); + EXPECT_LT(written, 0); + ASSERT_ERRNO_EQ(EOVERFLOW); +} diff --git a/libc/test/src/stdio/vfprintf_test.cpp b/libc/test/src/stdio/vfprintf_test.cpp index 8340bf90b30a8..9b5f09db8fd41 100644 --- a/libc/test/src/stdio/vfprintf_test.cpp +++ b/libc/test/src/stdio/vfprintf_test.cpp @@ -23,11 +23,6 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#if defined(LIBC_TARGET_OS_IS_LINUX) && \ - !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) -#include "src/stdio/fopencookie.h" -#endif - namespace printf_test { #ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE using LIBC_NAMESPACE::fclose; @@ -103,30 +98,3 @@ TEST(LlvmLibcVFPrintfTest, WriteToFile) { ASSERT_EQ(printf_test::fclose(file), 0); } - -#if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && \ - defined(LIBC_TARGET_OS_IS_LINUX) -TEST(LlvmLibcVFPrintfTest, CharsWrittenOverflow) { - struct NoopStream {}; - auto noop_write = [](void *, const char *, size_t size) -> ssize_t { - return size; - }; - - NoopStream stream; - cookie_io_functions_t funcs = {nullptr, +noop_write, nullptr, nullptr}; - ::FILE *file = LIBC_NAMESPACE::fopencookie(&stream, "w", funcs); - ASSERT_NE(file, nullptr); - - // Trigger an overflow in the return value of vfprintf by writing more than - // INT_MAX bytes. We do this by printing a string with precision INT_MAX, and - // then one more character. - int max_int = LIBC_NAMESPACE::cpp::numeric_limits::max(); - int result = call_vfprintf(file, "%*sA", max_int, ""); - - EXPECT_LT(result, 0); - ASSERT_ERRNO_EQ(EOVERFLOW); - - EXPECT_EQ(printf_test::fclose(file), 0); -} -#endif // !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && - // defined(LIBC_TARGET_OS_IS_LINUX) From 463e929121cc07557cc83b9a38dac1a2bee82b5d Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Thu, 23 Oct 2025 08:45:46 +0000 Subject: [PATCH 23/25] Add platfrom specific error converter implementations --- .../generic-error-number-macros.h | 1 - libc/src/stdio/CMakeLists.txt | 6 +++ libc/src/stdio/asprintf.cpp | 4 +- libc/src/stdio/baremetal/CMakeLists.txt | 2 + libc/src/stdio/baremetal/printf.cpp | 4 +- libc/src/stdio/baremetal/vprintf.cpp | 4 +- libc/src/stdio/generic/CMakeLists.txt | 1 + libc/src/stdio/generic/fprintf.cpp | 4 +- libc/src/stdio/generic/printf.cpp | 4 +- libc/src/stdio/generic/vfprintf.cpp | 4 +- libc/src/stdio/generic/vprintf.cpp | 4 +- libc/src/stdio/printf_core/CMakeLists.txt | 20 +++++++ .../printf_core/baremetal/CMakeLists.txt | 8 +++ .../printf_core/baremetal/error_converter.h | 49 +++++++++++++++++ libc/src/stdio/printf_core/core_structs.h | 31 +---------- libc/src/stdio/printf_core/error_converter.h | 22 ++++++++ .../stdio/printf_core/linux/CMakeLists.txt | 8 +++ .../stdio/printf_core/linux/error_converter.h | 54 +++++++++++++++++++ libc/src/stdio/snprintf.cpp | 4 +- libc/src/stdio/sprintf.cpp | 4 +- libc/src/stdio/vasprintf.cpp | 4 +- libc/src/stdio/vsnprintf.cpp | 4 +- libc/src/stdio/vsprintf.cpp | 4 +- libc/src/stdlib/CMakeLists.txt | 3 ++ libc/src/stdlib/strfromd.cpp | 4 +- libc/src/stdlib/strfromf.cpp | 4 +- libc/src/stdlib/strfroml.cpp | 4 +- 27 files changed, 219 insertions(+), 46 deletions(-) create mode 100644 libc/src/stdio/printf_core/baremetal/CMakeLists.txt create mode 100644 libc/src/stdio/printf_core/baremetal/error_converter.h create mode 100644 libc/src/stdio/printf_core/error_converter.h create mode 100644 libc/src/stdio/printf_core/linux/CMakeLists.txt create mode 100644 libc/src/stdio/printf_core/linux/error_converter.h diff --git a/libc/include/llvm-libc-macros/generic-error-number-macros.h b/libc/include/llvm-libc-macros/generic-error-number-macros.h index 5dd6eb2f97051..199a86217b347 100644 --- a/libc/include/llvm-libc-macros/generic-error-number-macros.h +++ b/libc/include/llvm-libc-macros/generic-error-number-macros.h @@ -43,7 +43,6 @@ #define EPIPE 32 #define EDOM 33 #define ERANGE 34 -#define EOVERFLOW 75 #define EILSEQ 84 #endif // LLVM_LIBC_MACROS_GENERIC_ERROR_NUMBER_MACROS_H diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt index 72fda8d343815..67da5bec258a0 100644 --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -126,6 +126,7 @@ add_entrypoint_object( libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer libc.src.stdio.printf_core.core_structs + libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno libc.hdr.errno_macros ) @@ -140,6 +141,7 @@ add_entrypoint_object( libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer libc.src.stdio.printf_core.core_structs + libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno libc.hdr.errno_macros ) @@ -153,6 +155,7 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.vasprintf_internal libc.src.stdio.printf_core.core_structs + libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno libc.hdr.errno_macros ) @@ -167,6 +170,7 @@ add_entrypoint_object( libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer libc.src.stdio.printf_core.core_structs + libc.src.stdio.printf_core.error_converter ) add_entrypoint_object( @@ -179,6 +183,7 @@ add_entrypoint_object( libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer libc.src.stdio.printf_core.core_structs + libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno libc.hdr.errno_macros ) @@ -192,6 +197,7 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.vasprintf_internal libc.src.stdio.printf_core.core_structs + libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno libc.hdr.errno_macros ) diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp index bb4077fa89542..a4852b75e4124 100644 --- a/libc/src/stdio/asprintf.cpp +++ b/libc/src/stdio/asprintf.cpp @@ -11,6 +11,7 @@ #include "src/__support/arg_list.h" #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/vasprintf_internal.h" namespace LIBC_NAMESPACE_DECL { @@ -30,7 +31,8 @@ LLVM_LIBC_FUNCTION(int, asprintf, return -1; } if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt index e4de151b109ed..af17635b9156a 100644 --- a/libc/src/stdio/baremetal/CMakeLists.txt +++ b/libc/src/stdio/baremetal/CMakeLists.txt @@ -29,6 +29,7 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer + libc.src.stdio.printf_core.error_converter libc.src.__support.arg_list libc.src.__support.OSUtil.osutil libc.src.__support.libc_errno @@ -88,6 +89,7 @@ add_entrypoint_object( DEPENDS libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer + libc.src.stdio.printf_core.error_converter libc.src.__support.arg_list libc.src.__support.OSUtil.osutil libc.src.__support.libc_errno diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index 7ce2bb5e256cb..74748a85ce614 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -12,6 +12,7 @@ #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -56,7 +57,8 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { } if (retval.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index e60260c49138d..19254d956a916 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -13,6 +13,7 @@ #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -55,7 +56,8 @@ LLVM_LIBC_FUNCTION(int, vprintf, } if (retval.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/generic/CMakeLists.txt b/libc/src/stdio/generic/CMakeLists.txt index 77ff3b76a4d1d..34ab478777e5e 100644 --- a/libc/src/stdio/generic/CMakeLists.txt +++ b/libc/src/stdio/generic/CMakeLists.txt @@ -395,6 +395,7 @@ list(APPEND fprintf_deps libc.src.__support.arg_list libc.src.stdio.printf_core.vfprintf_internal libc.src.stdio.printf_core.core_structs + libc.src.stdio.printf_core.error_converter ) if(LLVM_LIBC_FULL_BUILD) diff --git a/libc/src/stdio/generic/fprintf.cpp b/libc/src/stdio/generic/fprintf.cpp index 8251a098a9705..9b83986fb496f 100644 --- a/libc/src/stdio/generic/fprintf.cpp +++ b/libc/src/stdio/generic/fprintf.cpp @@ -11,6 +11,7 @@ #include "src/__support/File/file.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/vfprintf_internal.h" #include "hdr/types/FILE.h" @@ -33,7 +34,8 @@ LLVM_LIBC_FUNCTION(int, fprintf, return -1; } if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/generic/printf.cpp b/libc/src/stdio/generic/printf.cpp index 2ff1b35c02c07..2a40f59011a40 100644 --- a/libc/src/stdio/generic/printf.cpp +++ b/libc/src/stdio/generic/printf.cpp @@ -12,6 +12,7 @@ #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/vfprintf_internal.h" #include "hdr/types/FILE.h" @@ -39,7 +40,8 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { return -1; } if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/generic/vfprintf.cpp b/libc/src/stdio/generic/vfprintf.cpp index 280f8092a5520..a00a66d993962 100644 --- a/libc/src/stdio/generic/vfprintf.cpp +++ b/libc/src/stdio/generic/vfprintf.cpp @@ -12,6 +12,7 @@ #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/vfprintf_internal.h" #include "hdr/types/FILE.h" @@ -31,7 +32,8 @@ LLVM_LIBC_FUNCTION(int, vfprintf, return -1; } if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/generic/vprintf.cpp b/libc/src/stdio/generic/vprintf.cpp index ba9b283bf9655..155865f8dbf66 100644 --- a/libc/src/stdio/generic/vprintf.cpp +++ b/libc/src/stdio/generic/vprintf.cpp @@ -11,6 +11,7 @@ #include "src/__support/File/file.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/vfprintf_internal.h" #include "hdr/types/FILE.h" @@ -36,7 +37,8 @@ LLVM_LIBC_FUNCTION(int, vprintf, return -1; } if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt index dbb36ac96bc4c..baca2ffc82180 100644 --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -32,6 +32,16 @@ if(printf_config_copts) list(PREPEND printf_config_copts "COMPILE_OPTIONS") endif() +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + return() +endif() +add_subdirectory(${LIBC_TARGET_OS}) + +set(target_error_converter libc.src.stdio.printf_core.${LIBC_TARGET_OS}.${LIBC_TARGET_OS}_error_converter) +if(NOT TARGET ${target_error_converter}) + return() +endif() + add_header_library( printf_config HDRS @@ -143,6 +153,15 @@ add_header_library( libc.src.stdio.printf_core.writer ) +add_header_library( + error_converter + HDRS + error_converter.h + DEPENDS + ${target_error_converter} + libc.src.__support.macros.properties.architectures +) + if(NOT (TARGET libc.src.__support.File.file) AND LLVM_LIBC_FULL_BUILD) # Not all platforms have a file implementation. If file is unvailable, and a # full build is requested, then we must skip all file based printf sections. @@ -161,3 +180,4 @@ add_header_library( libc.src.stdio.printf_core.writer ${use_system_file} ) + diff --git a/libc/src/stdio/printf_core/baremetal/CMakeLists.txt b/libc/src/stdio/printf_core/baremetal/CMakeLists.txt new file mode 100644 index 0000000000000..2a436862e6afa --- /dev/null +++ b/libc/src/stdio/printf_core/baremetal/CMakeLists.txt @@ -0,0 +1,8 @@ +add_header_library( + baremetal_error_converter + HDRS + error_converter.h + DEPENDS + libc.src.stdio.printf_core.core_structs + libc.hdr.errno_macros +) diff --git a/libc/src/stdio/printf_core/baremetal/error_converter.h b/libc/src/stdio/printf_core/baremetal/error_converter.h new file mode 100644 index 0000000000000..5aabcfc8dc5c5 --- /dev/null +++ b/libc/src/stdio/printf_core/baremetal/error_converter.h @@ -0,0 +1,49 @@ +//===-- Baremetal implementation of error converter -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_BAREMETAL_ERROR_CONVERTER_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_BAREMETAL_ERROR_CONVERTER_H + +#include "hdr/errno_macros.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" + +namespace LIBC_NAMESPACE_DECL { +namespace printf_core { + +LIBC_INLINE static int internal_error_to_errno(int internal_error) { + // System error occured, return error as is. + if (internal_error < 1001 && internal_error > 0) { + return internal_error; + } + + // Map internal error to the available C standard errnos. + switch (-internal_error) { + case WRITE_OK: + return 0; + case FILE_WRITE_ERROR: + case FILE_STATUS_ERROR: + case NULLPTR_WRITE_ERROR: + case ALLOCATION_ERROR: + return EDOM; + case INT_CONVERSION_ERROR: + case FIXED_POINT_CONVERSION_ERROR: + case OVERFLOW_ERROR: + return ERANGE; + default: + LIBC_ASSERT( + false && + "Invalid internal printf error code passed to internal_error_to_errno"); + return EDOM; + } +} + +} // namespace printf_core +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_BAREMETAL_ERROR_CONVERTER_H diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index 7b205ee890c98..2f8188d1c4f8e 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -142,36 +142,7 @@ constexpr int NULLPTR_WRITE_ERROR = -1003; constexpr int INT_CONVERSION_ERROR = -1004; constexpr int FIXED_POINT_CONVERSION_ERROR = -1005; constexpr int ALLOCATION_ERROR = -1006; - -LIBC_INLINE static int internal_error_to_errno(int internal_error) { - // System error occured, return error as is. - if (internal_error < 1001) { - return internal_error; - } - - // Map internal error to errno. - switch (-internal_error) { - case WRITE_OK: - return 0; - case FILE_WRITE_ERROR: - return EIO; - case FILE_STATUS_ERROR: - return EIO; - case NULLPTR_WRITE_ERROR: - return EINVAL; - case INT_CONVERSION_ERROR: - return ERANGE; - case FIXED_POINT_CONVERSION_ERROR: - return EINVAL; - case ALLOCATION_ERROR: - return ENOMEM; - default: - LIBC_ASSERT( - false && - "Invalid internal printf error code passed to internal_error_to_errno"); - return EINVAL; - } -} +constexpr int OVERFLOW_ERROR = -1007; } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/error_converter.h b/libc/src/stdio/printf_core/error_converter.h new file mode 100644 index 0000000000000..6c4716267b27a --- /dev/null +++ b/libc/src/stdio/printf_core/error_converter.h @@ -0,0 +1,22 @@ +//===-- Error converter for printf ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_ERROR_CONVERTER_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_ERROR_CONVERTER_H + +#include "src/__support/macros/properties/architectures.h" + +// Maps internal errors to the available errnos on the platform. +#if defined(__linux__) +#include "linux/error_converter.h" +#elif defined(__ELF__) +// TODO: Ideally we would have LIBC_TARGET_OS_IS_BAREMETAL. +#include "baremetal/error_converter.h" +#endif + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_ERROR_CONVERTER_H diff --git a/libc/src/stdio/printf_core/linux/CMakeLists.txt b/libc/src/stdio/printf_core/linux/CMakeLists.txt new file mode 100644 index 0000000000000..4b193866a1914 --- /dev/null +++ b/libc/src/stdio/printf_core/linux/CMakeLists.txt @@ -0,0 +1,8 @@ +add_header_library( + linux_error_converter + HDRS + error_converter.h + DEPENDS + libc.src.stdio.printf_core.core_structs + libc.hdr.errno_macros +) diff --git a/libc/src/stdio/printf_core/linux/error_converter.h b/libc/src/stdio/printf_core/linux/error_converter.h new file mode 100644 index 0000000000000..9de24858bb3cf --- /dev/null +++ b/libc/src/stdio/printf_core/linux/error_converter.h @@ -0,0 +1,54 @@ +//===-- Linux implementation of error converter -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_LINUX_ERROR_CONVERTER_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_LINUX_ERROR_CONVERTER_H + +#include "hdr/errno_macros.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" + +namespace LIBC_NAMESPACE_DECL { +namespace printf_core { + +LIBC_INLINE static int internal_error_to_errno(int internal_error) { + // System error occured, return error as is. + if (internal_error < 1001 && internal_error > 0) { + return internal_error; + } + + // Map internal error to POSIX errnos. + switch (-internal_error) { + case WRITE_OK: + return 0; + case FILE_WRITE_ERROR: + return EIO; + case FILE_STATUS_ERROR: + return EIO; + case NULLPTR_WRITE_ERROR: + return EINVAL; + case INT_CONVERSION_ERROR: + return ERANGE; + case FIXED_POINT_CONVERSION_ERROR: + return EINVAL; + case ALLOCATION_ERROR: + return ENOMEM; + case OVERFLOW_ERROR: + return EOVERFLOW; + default: + LIBC_ASSERT( + false && + "Invalid internal printf error code passed to internal_error_to_errno"); + return EINVAL; + } +} + +} // namespace printf_core +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_LINUX_ERROR_CONVERTER_H diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp index 10b46ddfd6249..b703ac2894fb2 100644 --- a/libc/src/stdio/snprintf.cpp +++ b/libc/src/stdio/snprintf.cpp @@ -13,6 +13,7 @@ #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -44,7 +45,8 @@ LLVM_LIBC_FUNCTION(int, snprintf, wb.buff[wb.buff_cur] = '\0'; if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp index 53e951bea6aaa..343f75c595e2e 100644 --- a/libc/src/stdio/sprintf.cpp +++ b/libc/src/stdio/sprintf.cpp @@ -14,6 +14,7 @@ #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -44,7 +45,8 @@ LLVM_LIBC_FUNCTION(int, sprintf, wb.buff[wb.buff_cur] = '\0'; if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/vasprintf.cpp b/libc/src/stdio/vasprintf.cpp index 1060c39d416c1..fddc9e318cae6 100644 --- a/libc/src/stdio/vasprintf.cpp +++ b/libc/src/stdio/vasprintf.cpp @@ -11,6 +11,7 @@ #include "src/__support/arg_list.h" #include "src/__support/libc_errno.h" #include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/vasprintf_internal.h" namespace LIBC_NAMESPACE_DECL { @@ -27,7 +28,8 @@ LLVM_LIBC_FUNCTION(int, vasprintf, return -1; } if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } return static_cast(ret_val.value()); diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp index 000ec5d5cfa5b..aceae31c5ef3d 100644 --- a/libc/src/stdio/vsnprintf.cpp +++ b/libc/src/stdio/vsnprintf.cpp @@ -13,6 +13,7 @@ #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -41,7 +42,8 @@ LLVM_LIBC_FUNCTION(int, vsnprintf, wb.buff[wb.buff_cur] = '\0'; if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp index 5f8c79418e83d..8fef3fdbc9834 100644 --- a/libc/src/stdio/vsprintf.cpp +++ b/libc/src/stdio/vsprintf.cpp @@ -14,6 +14,7 @@ #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/printf_main.h" #include "src/stdio/printf_core/writer.h" @@ -41,7 +42,8 @@ LLVM_LIBC_FUNCTION(int, vsprintf, wb.buff[wb.buff_cur] = '\0'; if (ret_val.value() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } return static_cast(ret_val.value()); diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt index c464f82dcbda7..379fb39424f55 100644 --- a/libc/src/stdlib/CMakeLists.txt +++ b/libc/src/stdlib/CMakeLists.txt @@ -73,6 +73,7 @@ add_entrypoint_object( strfromf.h DEPENDS .str_from_util + libc.src.stdio.printf_core.error_converter ) add_entrypoint_object( @@ -83,6 +84,7 @@ add_entrypoint_object( strfromd.h DEPENDS .str_from_util + libc.src.stdio.printf_core.error_converter ) add_entrypoint_object( @@ -93,6 +95,7 @@ add_entrypoint_object( strfroml.h DEPENDS .str_from_util + libc.src.stdio.printf_core.error_converter ) add_header_library( diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp index c89f611831579..c402daa957e34 100644 --- a/libc/src/stdlib/strfromd.cpp +++ b/libc/src/stdlib/strfromd.cpp @@ -8,6 +8,7 @@ #include "src/stdlib/strfromd.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdlib/str_from_util.h" namespace LIBC_NAMESPACE_DECL { @@ -37,7 +38,8 @@ LLVM_LIBC_FUNCTION(int, strfromd, wb.buff[wb.buff_cur] = '\0'; if (writer.get_chars_written() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } return static_cast(writer.get_chars_written()); diff --git a/libc/src/stdlib/strfromf.cpp b/libc/src/stdlib/strfromf.cpp index 5c3e95f4146f2..53fb913d2a6b3 100644 --- a/libc/src/stdlib/strfromf.cpp +++ b/libc/src/stdlib/strfromf.cpp @@ -8,6 +8,7 @@ #include "src/stdlib/strfromf.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdlib/str_from_util.h" namespace LIBC_NAMESPACE_DECL { @@ -37,7 +38,8 @@ LLVM_LIBC_FUNCTION(int, strfromf, wb.buff[wb.buff_cur] = '\0'; if (writer.get_chars_written() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } return static_cast(writer.get_chars_written()); diff --git a/libc/src/stdlib/strfroml.cpp b/libc/src/stdlib/strfroml.cpp index 1605e8ab7c18f..aab0052931e7a 100644 --- a/libc/src/stdlib/strfroml.cpp +++ b/libc/src/stdlib/strfroml.cpp @@ -8,6 +8,7 @@ #include "src/stdlib/strfroml.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/error_converter.h" #include "src/stdlib/str_from_util.h" namespace LIBC_NAMESPACE_DECL { @@ -42,7 +43,8 @@ LLVM_LIBC_FUNCTION(int, strfroml, wb.buff[wb.buff_cur] = '\0'; if (writer.get_chars_written() > cpp::numeric_limits::max()) { - libc_errno = EOVERFLOW; + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); return -1; } return static_cast(writer.get_chars_written()); From 5f3b0af532865366d45ec751a6911439051db806 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Thu, 23 Oct 2025 09:18:26 +0000 Subject: [PATCH 24/25] Clean up dependencies --- libc/src/stdio/CMakeLists.txt | 5 ----- libc/src/stdio/asprintf.cpp | 2 +- libc/src/stdio/baremetal/CMakeLists.txt | 2 ++ libc/src/stdio/baremetal/vprintf.cpp | 1 - libc/src/stdio/generic/fprintf.cpp | 1 + libc/src/stdio/generic/vprintf.cpp | 1 + libc/src/stdio/printf_core/core_structs.h | 1 - libc/src/stdio/printf_core/int_converter.h | 1 - libc/src/stdio/printf_core/vasprintf_internal.h | 1 - libc/src/stdio/printf_core/write_int_converter.h | 1 - libc/src/stdio/snprintf.cpp | 1 - libc/src/stdio/sprintf.cpp | 1 - libc/src/stdio/vasprintf.cpp | 1 - libc/src/stdio/vsnprintf.cpp | 1 - libc/src/stdio/vsprintf.cpp | 1 - libc/src/stdlib/strfromd.cpp | 1 + libc/src/stdlib/strfromf.cpp | 1 + libc/src/stdlib/strfroml.cpp | 1 + libc/test/src/stdlib/StrfromTest.h | 1 - 19 files changed, 8 insertions(+), 17 deletions(-) diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt index 67da5bec258a0..7f8c95ef7b41e 100644 --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -128,7 +128,6 @@ add_entrypoint_object( libc.src.stdio.printf_core.core_structs libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno - libc.hdr.errno_macros ) add_entrypoint_object( @@ -143,7 +142,6 @@ add_entrypoint_object( libc.src.stdio.printf_core.core_structs libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno - libc.hdr.errno_macros ) add_entrypoint_object( @@ -157,7 +155,6 @@ add_entrypoint_object( libc.src.stdio.printf_core.core_structs libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno - libc.hdr.errno_macros ) add_entrypoint_object( @@ -185,7 +182,6 @@ add_entrypoint_object( libc.src.stdio.printf_core.core_structs libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno - libc.hdr.errno_macros ) add_entrypoint_object( @@ -199,7 +195,6 @@ add_entrypoint_object( libc.src.stdio.printf_core.core_structs libc.src.stdio.printf_core.error_converter libc.src.__support.libc_errno - libc.hdr.errno_macros ) add_subdirectory(printf_core) diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp index a4852b75e4124..49183c0614abc 100644 --- a/libc/src/stdio/asprintf.cpp +++ b/libc/src/stdio/asprintf.cpp @@ -7,10 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/stdio/asprintf.h" -#include "hdr/errno_macros.h" #include "src/__support/arg_list.h" #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/vasprintf_internal.h" diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt index af17635b9156a..3f97254356001 100644 --- a/libc/src/stdio/baremetal/CMakeLists.txt +++ b/libc/src/stdio/baremetal/CMakeLists.txt @@ -30,6 +30,7 @@ add_entrypoint_object( libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer libc.src.stdio.printf_core.error_converter + libc.src.stdio.printf_core.core_structs libc.src.__support.arg_list libc.src.__support.OSUtil.osutil libc.src.__support.libc_errno @@ -90,6 +91,7 @@ add_entrypoint_object( libc.src.stdio.printf_core.printf_main libc.src.stdio.printf_core.writer libc.src.stdio.printf_core.error_converter + libc.src.stdio.printf_core.core_structs libc.src.__support.arg_list libc.src.__support.OSUtil.osutil libc.src.__support.libc_errno diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index 19254d956a916..8170a3b16f22e 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "src/stdio/vprintf.h" -#include "hdr/errno_macros.h" #include "src/__support/OSUtil/io.h" #include "src/__support/arg_list.h" #include "src/__support/libc_errno.h" diff --git a/libc/src/stdio/generic/fprintf.cpp b/libc/src/stdio/generic/fprintf.cpp index 9b83986fb496f..6126a00665a9f 100644 --- a/libc/src/stdio/generic/fprintf.cpp +++ b/libc/src/stdio/generic/fprintf.cpp @@ -11,6 +11,7 @@ #include "src/__support/File/file.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/vfprintf_internal.h" diff --git a/libc/src/stdio/generic/vprintf.cpp b/libc/src/stdio/generic/vprintf.cpp index 155865f8dbf66..829cf232834e2 100644 --- a/libc/src/stdio/generic/vprintf.cpp +++ b/libc/src/stdio/generic/vprintf.cpp @@ -11,6 +11,7 @@ #include "src/__support/File/file.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/error_converter.h" #include "src/stdio/printf_core/vfprintf_internal.h" diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index 2f8188d1c4f8e..0d41f2244d8da 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -11,7 +11,6 @@ #include "src/__support/macros/config.h" -#include "hdr/errno_macros.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" diff --git a/libc/src/stdio/printf_core/int_converter.h b/libc/src/stdio/printf_core/int_converter.h index 61cb402732ab7..11234c32ce997 100644 --- a/libc/src/stdio/printf_core/int_converter.h +++ b/libc/src/stdio/printf_core/int_converter.h @@ -9,7 +9,6 @@ #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H -#include "hdr/errno_macros.h" #include "src/__support/CPP/span.h" #include "src/__support/CPP/string_view.h" #include "src/__support/ctype_utils.h" diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h index 50ebf0ea4555d..41df17b67f35b 100644 --- a/libc/src/stdio/printf_core/vasprintf_internal.h +++ b/libc/src/stdio/printf_core/vasprintf_internal.h @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "hdr/errno_macros.h" #include "hdr/func/free.h" #include "hdr/func/malloc.h" #include "hdr/func/realloc.h" diff --git a/libc/src/stdio/printf_core/write_int_converter.h b/libc/src/stdio/printf_core/write_int_converter.h index f63a9a538690d..04b2bef05bc7b 100644 --- a/libc/src/stdio/printf_core/write_int_converter.h +++ b/libc/src/stdio/printf_core/write_int_converter.h @@ -9,7 +9,6 @@ #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITE_INT_CONVERTER_H #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITE_INT_CONVERTER_H -#include "hdr/errno_macros.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/writer.h" diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp index b703ac2894fb2..25da3a9dbd2c5 100644 --- a/libc/src/stdio/snprintf.cpp +++ b/libc/src/stdio/snprintf.cpp @@ -8,7 +8,6 @@ #include "src/stdio/snprintf.h" -#include "hdr/errno_macros.h" #include "src/__support/arg_list.h" #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp index 343f75c595e2e..09f222927afd6 100644 --- a/libc/src/stdio/sprintf.cpp +++ b/libc/src/stdio/sprintf.cpp @@ -8,7 +8,6 @@ #include "src/stdio/sprintf.h" -#include "hdr/errno_macros.h" #include "src/__support/CPP/limits.h" #include "src/__support/arg_list.h" #include "src/__support/libc_errno.h" diff --git a/libc/src/stdio/vasprintf.cpp b/libc/src/stdio/vasprintf.cpp index fddc9e318cae6..d1ac9f4342824 100644 --- a/libc/src/stdio/vasprintf.cpp +++ b/libc/src/stdio/vasprintf.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "src/stdio/vasprintf.h" -#include "hdr/errno_macros.h" #include "src/__support/arg_list.h" #include "src/__support/libc_errno.h" #include "src/stdio/printf_core/core_structs.h" diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp index aceae31c5ef3d..01ece7d04df7e 100644 --- a/libc/src/stdio/vsnprintf.cpp +++ b/libc/src/stdio/vsnprintf.cpp @@ -8,7 +8,6 @@ #include "src/stdio/vsnprintf.h" -#include "hdr/errno_macros.h" #include "src/__support/arg_list.h" #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp index 8fef3fdbc9834..3b1a4a37bc405 100644 --- a/libc/src/stdio/vsprintf.cpp +++ b/libc/src/stdio/vsprintf.cpp @@ -8,7 +8,6 @@ #include "src/stdio/vsprintf.h" -#include "hdr/errno_macros.h" #include "src/__support/CPP/limits.h" #include "src/__support/arg_list.h" #include "src/__support/libc_errno.h" diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp index c402daa957e34..dce1b5e5f253f 100644 --- a/libc/src/stdlib/strfromd.cpp +++ b/libc/src/stdlib/strfromd.cpp @@ -8,6 +8,7 @@ #include "src/stdlib/strfromd.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/error_converter.h" #include "src/stdlib/str_from_util.h" diff --git a/libc/src/stdlib/strfromf.cpp b/libc/src/stdlib/strfromf.cpp index 53fb913d2a6b3..fe811ee27242f 100644 --- a/libc/src/stdlib/strfromf.cpp +++ b/libc/src/stdlib/strfromf.cpp @@ -8,6 +8,7 @@ #include "src/stdlib/strfromf.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/error_converter.h" #include "src/stdlib/str_from_util.h" diff --git a/libc/src/stdlib/strfroml.cpp b/libc/src/stdlib/strfroml.cpp index aab0052931e7a..ef27312d026c2 100644 --- a/libc/src/stdlib/strfroml.cpp +++ b/libc/src/stdlib/strfroml.cpp @@ -8,6 +8,7 @@ #include "src/stdlib/strfroml.h" #include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/error_converter.h" #include "src/stdlib/str_from_util.h" diff --git a/libc/test/src/stdlib/StrfromTest.h b/libc/test/src/stdlib/StrfromTest.h index 1442f172e19fe..fdeed0e3c06f5 100644 --- a/libc/test/src/stdlib/StrfromTest.h +++ b/libc/test/src/stdlib/StrfromTest.h @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "src/__support/CPP/limits.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" #include "test/UnitTest/ErrnoCheckingTest.h" From 428c7e9a5464a0e0a31dc585a89d46da9d0b8e21 Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Thu, 23 Oct 2025 10:42:52 +0000 Subject: [PATCH 25/25] Add darwin and generic impl of error converter --- libc/src/stdio/printf_core/CMakeLists.txt | 9 ++-- .../{baremetal => darwin}/CMakeLists.txt | 2 +- .../printf_core/darwin/error_converter.h | 54 +++++++++++++++++++ libc/src/stdio/printf_core/error_converter.h | 7 +-- .../stdio/printf_core/generic/CMakeLists.txt | 8 +++ .../{baremetal => generic}/error_converter.h | 8 +-- 6 files changed, 76 insertions(+), 12 deletions(-) rename libc/src/stdio/printf_core/{baremetal => darwin}/CMakeLists.txt (82%) create mode 100644 libc/src/stdio/printf_core/darwin/error_converter.h create mode 100644 libc/src/stdio/printf_core/generic/CMakeLists.txt rename libc/src/stdio/printf_core/{baremetal => generic}/error_converter.h (82%) diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt index baca2ffc82180..016543bbfb535 100644 --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -32,14 +32,15 @@ if(printf_config_copts) list(PREPEND printf_config_copts "COMPILE_OPTIONS") endif() -if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) - return() +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${LIBC_TARGET_OS}) +else() + add_subdirectory(generic) endif() -add_subdirectory(${LIBC_TARGET_OS}) set(target_error_converter libc.src.stdio.printf_core.${LIBC_TARGET_OS}.${LIBC_TARGET_OS}_error_converter) if(NOT TARGET ${target_error_converter}) - return() + set(target_error_converter libc.src.stdio.printf_core.generic.generic_error_converter) endif() add_header_library( diff --git a/libc/src/stdio/printf_core/baremetal/CMakeLists.txt b/libc/src/stdio/printf_core/darwin/CMakeLists.txt similarity index 82% rename from libc/src/stdio/printf_core/baremetal/CMakeLists.txt rename to libc/src/stdio/printf_core/darwin/CMakeLists.txt index 2a436862e6afa..89bc59097764c 100644 --- a/libc/src/stdio/printf_core/baremetal/CMakeLists.txt +++ b/libc/src/stdio/printf_core/darwin/CMakeLists.txt @@ -1,5 +1,5 @@ add_header_library( - baremetal_error_converter + darwin_error_converter HDRS error_converter.h DEPENDS diff --git a/libc/src/stdio/printf_core/darwin/error_converter.h b/libc/src/stdio/printf_core/darwin/error_converter.h new file mode 100644 index 0000000000000..897c76ffe7099 --- /dev/null +++ b/libc/src/stdio/printf_core/darwin/error_converter.h @@ -0,0 +1,54 @@ +//===-- Darwin implementation of error converter ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_DARWIN_ERROR_CONVERTER_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_DARWIN_ERROR_CONVERTER_H + +#include "hdr/errno_macros.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_converter.h" + +namespace LIBC_NAMESPACE_DECL { +namespace printf_core { + +LIBC_INLINE static int internal_error_to_errno(int internal_error) { + // System error occured, return error as is. + if (internal_error < 1001 && internal_error > 0) { + return internal_error; + } + + // Map internal error to POSIX errnos. + switch (-internal_error) { + case WRITE_OK: + return 0; + case FILE_WRITE_ERROR: + return EIO; + case FILE_STATUS_ERROR: + return EIO; + case NULLPTR_WRITE_ERROR: + return EINVAL; + case INT_CONVERSION_ERROR: + return ERANGE; + case FIXED_POINT_CONVERSION_ERROR: + return EINVAL; + case ALLOCATION_ERROR: + return ENOMEM; + case OVERFLOW_ERROR: + return EOVERFLOW; + default: + LIBC_ASSERT( + false && + "Invalid internal printf error code passed to internal_error_to_errno"); + return EINVAL; + } +} + +} // namespace printf_core +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_DARWIN_ERROR_CONVERTER_H diff --git a/libc/src/stdio/printf_core/error_converter.h b/libc/src/stdio/printf_core/error_converter.h index 6c4716267b27a..f2fe303203fc7 100644 --- a/libc/src/stdio/printf_core/error_converter.h +++ b/libc/src/stdio/printf_core/error_converter.h @@ -14,9 +14,10 @@ // Maps internal errors to the available errnos on the platform. #if defined(__linux__) #include "linux/error_converter.h" -#elif defined(__ELF__) -// TODO: Ideally we would have LIBC_TARGET_OS_IS_BAREMETAL. -#include "baremetal/error_converter.h" +#elif defined(__APPLE__) +#include "darwin/error_converter.h" +#else +#include "generic/error_converter.h" #endif #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_ERROR_CONVERTER_H diff --git a/libc/src/stdio/printf_core/generic/CMakeLists.txt b/libc/src/stdio/printf_core/generic/CMakeLists.txt new file mode 100644 index 0000000000000..f7fc250734645 --- /dev/null +++ b/libc/src/stdio/printf_core/generic/CMakeLists.txt @@ -0,0 +1,8 @@ +add_header_library( + generic_error_converter + HDRS + error_converter.h + DEPENDS + libc.src.stdio.printf_core.core_structs + libc.hdr.errno_macros +) diff --git a/libc/src/stdio/printf_core/baremetal/error_converter.h b/libc/src/stdio/printf_core/generic/error_converter.h similarity index 82% rename from libc/src/stdio/printf_core/baremetal/error_converter.h rename to libc/src/stdio/printf_core/generic/error_converter.h index 5aabcfc8dc5c5..2f59a105415c7 100644 --- a/libc/src/stdio/printf_core/baremetal/error_converter.h +++ b/libc/src/stdio/printf_core/generic/error_converter.h @@ -1,4 +1,4 @@ -//===-- Baremetal implementation of error converter -------------*- C++ -*-===// +//===-- Generic implementation of error converter ---------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_BAREMETAL_ERROR_CONVERTER_H -#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_BAREMETAL_ERROR_CONVERTER_H +#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_GENERIC_ERROR_CONVERTER_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_GENERIC_ERROR_CONVERTER_H #include "hdr/errno_macros.h" #include "src/stdio/printf_core/core_structs.h" @@ -46,4 +46,4 @@ LIBC_INLINE static int internal_error_to_errno(int internal_error) { } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL -#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_BAREMETAL_ERROR_CONVERTER_H +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_GENERIC_ERROR_CONVERTER_H