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