Tested x86_64-linux. Pushed to trunk. gcc-13 backport to follow. -- >8 --
At the end of a replacement field we should check that the closing brace is actually present before incrementing past it. libstdc++-v3/ChangeLog: PR libstdc++/110862 * include/std/format (_Scanner::_M_on_replacement_field): Check for expected '}' before incrementing iterator. * testsuite/std/format/string.cc: Check "{0:{0}" format string. --- libstdc++-v3/include/std/format | 4 +++- libstdc++-v3/testsuite/std/format/string.cc | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 1e0ef612ddd..0debbae5ba8 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -3534,7 +3534,9 @@ namespace __format _M_pc.advance_to(__ptr); } _M_format_arg(__id); - _M_pc.advance_to(_M_pc.begin() + 1); // Move past '}' + if (begin() == end() || *begin() != '}') + __format::__unmatched_left_brace_in_format_string(); + _M_pc.advance_to(begin() + 1); // Move past '}' } constexpr virtual void _M_format_arg(size_t __id) = 0; diff --git a/libstdc++-v3/testsuite/std/format/string.cc b/libstdc++-v3/testsuite/std/format/string.cc index d28135ec260..6a45237b8c4 100644 --- a/libstdc++-v3/testsuite/std/format/string.cc +++ b/libstdc++-v3/testsuite/std/format/string.cc @@ -128,6 +128,19 @@ test_format_spec() VERIFY( ! is_format_string_for("{:9999999}", 1) ); } +void +test_pr110862() +{ + try { + // PR libstdc++/110862 out-of-bounds read on invalid format string + (void) std::vformat("{0:{0}", std::make_format_args(1)); + VERIFY( false ); + } catch (const std::format_error& e) { + std::string_view what = e.what(); + VERIFY( what.find("unmatched left brace") != what.npos ); + } +} + int main() { test_no_args(); -- 2.41.0