Author: Mark de Wever
Date: 2023-08-31T09:00:27+02:00
New Revision: 078e20cade5518d7df48c75ac25c3179f825f70a

URL: 
https://github.com/llvm/llvm-project/commit/078e20cade5518d7df48c75ac25c3179f825f70a
DIFF: 
https://github.com/llvm/llvm-project/commit/078e20cade5518d7df48c75ac25c3179f825f70a.diff

LOG: [libc++][format] Fixes out of bounds access.

Fixes https://llvm.org/PR65011

Reviewed By: #libc, ldionne

Differential Revision: https://reviews.llvm.org/D158940

(cherry picked from commit 8930d04d5580c6a2cf04545c87387cd150cd7b46)

Added: 
    

Modified: 
    libcxx/include/__format/format_functions.h
    libcxx/test/std/utilities/format/format.functions/format_tests.h
    libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__format/format_functions.h 
b/libcxx/include/__format/format_functions.h
index 27ec0a295f4f43..bb62c1ce10c15c 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -245,6 +245,9 @@ __handle_replacement_field(_Iterator __begin, _Iterator 
__end,
   using _CharT = iter_value_t<_Iterator>;
   __format::__parse_number_result __r = __format::__parse_arg_id(__begin, 
__end, __parse_ctx);
 
+  if (__r.__last == __end)
+    std::__throw_format_error("The argument index should end with a ':' or a 
'}'");
+
   bool __parse = *__r.__last == _CharT(':');
   switch (*__r.__last) {
   case _CharT(':'):

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_tests.h 
b/libcxx/test/std/utilities/format/format.functions/format_tests.h
index 7a9cdaab7e93e8..0a5c6649240d68 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_tests.h
+++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h
@@ -3145,8 +3145,13 @@ void format_tests(TestFunction check, ExceptionTest 
check_exception) {
 
   // *** Test invalid format strings ***
   check_exception("The format string terminates at a '{'", SV("{"));
+  check_exception("The argument index value is too large for the number of 
arguments supplied", SV("{:"));
   check_exception("The replacement field misses a terminating '}'", SV("{:"), 
42);
 
+  check_exception("The argument index should end with a ':' or a '}'", 
SV("{0"));
+  check_exception("The argument index value is too large for the number of 
arguments supplied", SV("{0:"));
+  check_exception("The replacement field misses a terminating '}'", SV("{0:"), 
42);
+
   check_exception("The format string contains an invalid escape sequence", 
SV("}"));
   check_exception("The format string contains an invalid escape sequence", 
SV("{:}-}"), 42);
 

diff  --git 
a/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp 
b/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
index 6943ddc2f968ec..e16d50f18284f7 100644
--- a/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
@@ -50,6 +50,17 @@ auto test_exception =
     };
 
 int main(int, char**) {
+#if !defined(TEST_HAS_NO_EXCEPTIONS)
+  // reproducer of https://llvm.org/PR65011
+  try {
+    const char fmt[] = {'{', '0'};
+    char buf[4096];
+    [[maybe_unused]] auto ignored =
+        std::vformat_to(buf, std::string_view{fmt, fmt + sizeof(fmt)}, 
std::make_format_args());
+  } catch (...) {
+  }
+#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
+
   format_tests<char, execution_modus::full>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS


        
_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to