This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit e7dbe57388af2cd0044c27ad77437edc74e97e6e Author: Marco Casaroli <[email protected]> AuthorDate: Thu Nov 5 06:51:56 2026 +0100 libs/libc/stream: Fail with EOVERFLOW when the output passes INT_MAX. printf() added each part of the output to an int, without a limit. "%*d%*d" with two large widths had a signed overflow and returned a negative value that is not -1. A caller of vasprintf() or of snprintf() then uses a wrong size. Keep the total in a size_t. Stop when it passes INT_MAX, and then return -1 with errno set to EOVERFLOW, as POSIX specifies. A conversion with a length above INT_MAX fails before its output, so one conversion adds at most INT_MAX and the total does not wrap. Part of https://github.com/apache/nuttx/issues/21467 Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- libs/libc/stream/lib_libvsprintf.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/libs/libc/stream/lib_libvsprintf.c b/libs/libc/stream/lib_libvsprintf.c index 5ebb2c3b98b..4e58aa02b7d 100644 --- a/libs/libc/stream/lib_libvsprintf.c +++ b/libs/libc/stream/lib_libvsprintf.c @@ -47,6 +47,7 @@ #endif #include <assert.h> +#include <errno.h> #include <limits.h> #include <string.h> #include <wchar.h> @@ -227,7 +228,7 @@ static int vsprintf_internal(FAR struct lib_outstream_s *stream, int ch; int star; unsigned int len; - int total_len = 0; + size_t total_len = 0; #ifdef CONFIG_LIBC_NUMBERED_ARGS int argnumber = 0; @@ -236,7 +237,7 @@ static int vsprintf_internal(FAR struct lib_outstream_s *stream, UNUSED(numargs); #endif - for (; ; ) + while (total_len <= INT_MAX) { #ifndef CONFIG_ARCH_ROMGETC FAR const char *start = fmt; @@ -840,6 +841,12 @@ flt_oper: flen += 1; } + if (flen > INT_MAX) + { + total_len = INT_MAX + 1u; + goto ret; + } + width = width > flen ? width - flen : 0; /* Output before first digit */ @@ -1044,8 +1051,7 @@ flt_oper: size = wcrtomb(buf, (wchar_t)ch, &ps); if (size == (size_t)-1) { - total_len = -1; - goto ret; + return -1; } } else @@ -1105,8 +1111,7 @@ flt_oper: n = wcrtomb(mb, ws[i], &ps); if (n == (size_t)-1) { - total_len = -1; - goto ret; + return -1; } if ((flags & FL_PREC) != 0 && size + n > (size_t)prec) @@ -1464,6 +1469,12 @@ str_lpad: len += 1; } + if (len > INT_MAX) + { + total_len = INT_MAX + 1u; + goto ret; + } + if ((flags & FL_LPAD) == 0) { if ((flags & FL_ZFILL) != 0) @@ -1529,6 +1540,12 @@ tail: } ret: + if (total_len > INT_MAX) + { + set_errno(EOVERFLOW); + return -1; + } + return total_len; }
