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 e45a1ee8eb5647bbc8de822852659c90cec8b361 Author: Marco Casaroli <[email protected]> AuthorDate: Thu Nov 5 06:51:54 2026 +0100 libs/libc/stream: Record the type of each numbered argument. lib_vsprintf() reads the numbered arguments between two passes over the format, with the types from the first pass. arglist.type[] had no initial value, and the first pass had no type for %x, %X, %o, %S and %n and for an argument number that the format does not use. So "%2$s %1$x" skipped an argument or read one with a size from uninitialized memory, and the %s got a wrong pointer. "%2$s%1$n" printed from an uninitialized stack. Clear arglist.type[] and record the type of these conversions. At a number that the format does not use, the size is not known and the place of the next arguments is also not known: read only the arguments before it. A conversion with a number after that ends the output, as a number above NL_ARGMAX does. 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 | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/libs/libc/stream/lib_libvsprintf.c b/libs/libc/stream/lib_libvsprintf.c index 80083855c1c..a53292a79d5 100644 --- a/libs/libc/stream/lib_libvsprintf.c +++ b/libs/libc/stream/lib_libvsprintf.c @@ -605,7 +605,8 @@ static int vsprintf_internal(FAR struct lib_outstream_s *stream, { arglist->type[argnumber - 1] = TYPE_DOUBLE; } - else if (c == 'i' || c == 'd' || c == 'u' || c == 'p') + else if (c == 'i' || c == 'd' || c == 'u' || c == 'p' || + c == 'o' || c == 'x' || c == 'X') { if ((flags & FL_LONG) == 0) { @@ -624,7 +625,7 @@ static int vsprintf_internal(FAR struct lib_outstream_s *stream, { arglist->type[argnumber - 1] = TYPE_INT; } - else if (c == 's') + else if (c == 's' || c == 'S' || c == 'n') { arglist->type[argnumber - 1] = TYPE_CHAR_POINTER; } @@ -1524,7 +1525,11 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream, #ifdef CONFIG_LIBC_NUMBERED_ARGS /* We do 2 passes of parsing and fill the arglist between the passes. */ - struct arg_s arglist; + struct arg_s arglist = + { + { 0 } + }; + int numargs = vsprintf_internal(NULL, &arglist, NL_ARGMAX, fmt, ap); union arg_u argvalue[MAX(numargs, 1)]; int i; @@ -1556,6 +1561,15 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream, case TYPE_CHAR_POINTER: arglist.value[i].cp = va_arg(ap, FAR char *); break; + + default: + + /* A number was not used, so its size is not known and the next + * arguments cannot be found. Use only the arguments before it. + */ + + numargs = i; + break; } }
