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 8cf131aaf672c39b75c44c929cc1c539f27cecfe Author: Marco Casaroli <[email protected]> AuthorDate: Thu Nov 5 06:51:55 2026 +0100 libs/libc/stream: Stop at an unknown conversion and at the format end. An unknown conversion took an unsigned int, printed the conversion as text and went on. Its argument can have any size, so the arguments after it were wrong, and a later %s could use a wrong pointer. This also hits a valid format of a newer standard that printf() does not know yet: %w64d %s on a 32-bit CPU, %w32d %s where int has 16 bits, %Hf %s on arm64. A format that ends after "%", a flag, a width or a length, such as "%" or "%5", was the same case with a NUL as the conversion. The output got a NUL, and the next loop read the format past its end. The first pass for the numbered arguments also read past the end. Now print "%" and the character, print the rest of the format as text, take no more arguments, and end. At the end of the format, print only "%". The first pass stops at the same place. 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 | 110 ++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 49 deletions(-) diff --git a/libs/libc/stream/lib_libvsprintf.c b/libs/libc/stream/lib_libvsprintf.c index a53292a79d5..3629aa1c0ee 100644 --- a/libs/libc/stream/lib_libvsprintf.c +++ b/libs/libc/stream/lib_libvsprintf.c @@ -595,57 +595,58 @@ static int vsprintf_internal(FAR struct lib_outstream_s *stream, } #ifdef CONFIG_LIBC_NUMBERED_ARGS - if ((flags & FL_ARGNUMBER) != 0) + if ((flags & FL_ARGNUMBER) != 0 && argnumber > numargs) { - if (argnumber > 0 && argnumber <= numargs) - { - if (stream == NULL) - { - if (fmt_isfloat(c)) - { - arglist->type[argnumber - 1] = TYPE_DOUBLE; - } - else if (c == 'i' || c == 'd' || c == 'u' || c == 'p' || - c == 'o' || c == 'x' || c == 'X') - { - if ((flags & FL_LONG) == 0) - { - arglist->type[argnumber - 1] = TYPE_INT; - } - else if ((flags & FL_REPD_TYPE) == 0) - { - arglist->type[argnumber - 1] = TYPE_LONG; - } - else - { - arglist->type[argnumber - 1] = TYPE_LONG_LONG; - } - } - else if (c == 'c') - { - arglist->type[argnumber - 1] = TYPE_INT; - } - else if (c == 's' || c == 'S' || c == 'n') - { - arglist->type[argnumber - 1] = TYPE_CHAR_POINTER; - } + goto ret; + } - if (argnumber > total_len) - { - total_len = argnumber; - } + if (stream == NULL) + { + unsigned char type; /* We do only parsing */ - continue; /* We do only parsing */ + if (fmt_isfloat(c)) + { + type = TYPE_DOUBLE; + } + else if (c == 'i' || c == 'd' || c == 'u' || c == 'p' || + c == 'o' || c == 'x' || c == 'X') + { + if ((flags & FL_LONG) == 0) + { + type = TYPE_INT; + } + else if ((flags & FL_REPD_TYPE) == 0) + { + type = TYPE_LONG; } + else + { + type = TYPE_LONG_LONG; + } + } + else if (c == 'c') + { + type = TYPE_INT; + } + else if (c == 's' || c == 'S' || c == 'n') + { + type = TYPE_CHAR_POINTER; } else { - goto ret; + goto ret; /* The second pass reads no argument after this */ } - } - else if (stream == NULL) - { - continue; /* We do only parsing */ + + if ((flags & FL_ARGNUMBER) != 0) + { + arglist->type[argnumber - 1] = type; + if (argnumber > total_len) + { + total_len = argnumber; + } + } + + continue; } #endif @@ -1238,6 +1239,22 @@ str_lpad: c = __ultoa_invert(x, buf, 10) - buf; } } + else if (c != 'u' && c != 'o' && c != 'p' && (c | 0x20) != 'x') + { + /* An unknown conversion, or the end of the format. The size of + * the argument is not known, so read no more arguments. Print the + * rest of the format as it is. + */ + + stream_putc('%', stream); + while (c != '\0') + { + stream_putc(c, stream); + c = fmt_char(fmt); + } + + goto ret; + } else { int base; @@ -1385,7 +1402,7 @@ str_lpad: base = 16; break; - case 'X': + default: /* 'X' */ if ((flags & FL_ALT) != 0) { flags |= (FL_ALTHEX | FL_ALTUPP); @@ -1393,11 +1410,6 @@ str_lpad: base = 16 | XTOA_UPPER; break; - - default: - stream_putc('%', stream); - stream_putc(c, stream); - continue; } if ((flags & FL_PREC) != 0 && prec == 0 && x == 0)
