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)

Reply via email to