[libc-commits] [libc] [libc][stdio] Add support for the %m modifier (PR #218312)

via libc-commits libc-commits at lists.llvm.org
Sun Aug 23 21:01:39 PDT 2026


https://github.com/afnrow created https://github.com/llvm/llvm-project/pull/218312

Add support for the %m modifier and it's derivatives as per
POSIX 2008.1 by leveraging the preexisting FormatFlags::Allocate
and allocating 32 bytes at a time that scale by 2x on each iteration
till it reaches the desired outcome.

>From 8d7e917c8b17224a3dd5ddeffe55ccc84cac5e98 Mon Sep 17 00:00:00 2001
From: yahia ahmed <yahia.a.abdrabou at gmail.com>
Date: Mon, 24 Aug 2026 07:00:01 +0300
Subject: [PATCH] [libc][stdio] Add support for the %m modifier

---
 libc/src/stdio/scanf_core/CMakeLists.txt      |  1 +
 libc/src/stdio/scanf_core/parser.h            |  9 ++--
 libc/src/stdio/scanf_core/string_converter.h  | 51 +++++++++++++++++--
 libc/test/src/stdio/scanf_core/CMakeLists.txt |  1 +
 4 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/libc/src/stdio/scanf_core/CMakeLists.txt b/libc/src/stdio/scanf_core/CMakeLists.txt
index fd68f5d21ae7f..e566103afa904 100644
--- a/libc/src/stdio/scanf_core/CMakeLists.txt
+++ b/libc/src/stdio/scanf_core/CMakeLists.txt
@@ -105,6 +105,7 @@ add_header_library(
     libc.src.__support.CPP.limits
     libc.src.__support.char_vector
     libc.src.__support.str_to_float
+    libc.src.__support.CPP.new
     ${use_system_file}
 )
 
diff --git a/libc/src/stdio/scanf_core/parser.h b/libc/src/stdio/scanf_core/parser.h
index 1e2f26e0d3fdd..37e49e6878796 100644
--- a/libc/src/stdio/scanf_core/parser.h
+++ b/libc/src/stdio/scanf_core/parser.h
@@ -81,11 +81,10 @@ template <typename ArgProvider> class Parser {
         cur_pos = cur_pos + static_cast<size_t>(result.parsed_len);
       }
 
-      // TODO(michaelrj): add posix allocate flag support.
-      // if (str[cur_pos] == 'm') {
-      //   ++cur_pos;
-      //   section.flags = FormatFlags::ALLOCATE;
-      // }
+      if (str[cur_pos] == 'm') {
+        ++cur_pos;
+        section.flags = FormatFlags::ALLOCATE;
+      }
 
       LengthModifier lm = parse_length_modifier(&cur_pos);
       section.length_modifier = lm;
diff --git a/libc/src/stdio/scanf_core/string_converter.h b/libc/src/stdio/scanf_core/string_converter.h
index 3879f8c995899..6ed9ea26dcc49 100644
--- a/libc/src/stdio/scanf_core/string_converter.h
+++ b/libc/src/stdio/scanf_core/string_converter.h
@@ -10,10 +10,14 @@
 #define LLVM_LIBC_SRC_STDIO_SCANF_CORE_STRING_CONVERTER_H
 
 #include "src/__support/CPP/limits.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/ctype_utils.h"
+#include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
 #include "src/stdio/scanf_core/core_structs.h"
 #include "src/stdio/scanf_core/reader.h"
+#include "src/string/memory_utils/inline_memcpy.h"
 
 #include <stddef.h>
 
@@ -40,8 +44,21 @@ int convert_string(Reader<T> *reader, const FormatSection &to_conv) {
     }
   }
 
-  char *output = reinterpret_cast<char *>(to_conv.output_ptr);
-
+  char *output;
+  size_t value;
+  AllocChecker ac;
+  if ((to_conv.flags & NO_WRITE) == 0 && (to_conv.flags & ALLOCATE) != 0) {
+    if (to_conv.conv_name == 'c')
+      value = max_width + 1;
+    else
+      value = (max_width < 32) ? max_width + 1 : 32;
+    output = new (ac) char[value];
+    if (!ac) {
+      libc_errno = ENOMEM;
+      return MATCHING_FAILURE;
+    }
+  } else
+    output = reinterpret_cast<char *>(to_conv.output_ptr);
   char cur_char = reader->getc();
   size_t i = 0;
   for (; i < max_width && cur_char != '\0'; ++i) {
@@ -53,7 +70,24 @@ int convert_string(Reader<T> *reader, const FormatSection &to_conv) {
     }
     // if the NO_WRITE flag is not set, write to the output.
     if ((to_conv.flags & NO_WRITE) == 0)
-      output[i] = cur_char;
+      if ((to_conv.flags & NO_WRITE) == 0) {
+        output[i] = cur_char;
+        if ((to_conv.flags & ALLOCATE) != 0) {
+          if ((i + 1) == value && value < max_width) {
+            value *= 2;
+            char *tmp = new (ac) char[value];
+            if (!ac) {
+              delete[] output;
+              libc_errno = ENOMEM;
+              reader->ungetc(cur_char);
+              return MATCHING_FAILURE;
+            }
+            inline_memcpy(tmp, output, i + 1);
+            delete[] output;
+            output = tmp;
+          }
+        }
+      }
     cur_char = reader->getc();
   }
 
@@ -70,8 +104,17 @@ int convert_string(Reader<T> *reader, const FormatSection &to_conv) {
     output[i] = '\0';
   }
 
-  if (i == 0)
+  if (i == 0) {
+    if ((to_conv.flags & ALLOCATE) != 0 && output)
+      delete[] output;
     return MATCHING_FAILURE;
+  }
+
+  if ((to_conv.flags & ALLOCATE) != 0) {
+    char **outptr = reinterpret_cast<char **>(to_conv.output_ptr);
+    *outptr = output;
+  }
+
   return READ_OK;
 }
 
diff --git a/libc/test/src/stdio/scanf_core/CMakeLists.txt b/libc/test/src/stdio/scanf_core/CMakeLists.txt
index 6fdee7b3d5d51..0b234c6054721 100644
--- a/libc/test/src/stdio/scanf_core/CMakeLists.txt
+++ b/libc/test/src/stdio/scanf_core/CMakeLists.txt
@@ -47,6 +47,7 @@ add_libc_test(
     libc.src.stdio.scanf_core.converter
     libc.src.stdio.scanf_core.string_reader
     libc.src.__support.CPP.string_view
+    libc.src.__support.CPP.new
   COMPILE_OPTIONS
     ${use_system_file}
 )



More information about the libc-commits mailing list