https://gcc.gnu.org/g:6c61f43b8cd410125026429a6ea87308dd49a786
commit r13-9500-g6c61f43b8cd410125026429a6ea87308dd49a786 Author: Jonathan Wakely <jwak...@redhat.com> Date: Mon Apr 7 19:52:55 2025 +0100 libstdc++: Fix use-after-free in std::format [PR119671] When formatting floating-point values to wide strings there's a case where we invalidate a std::wstring buffer while a std::wstring_view is still referring to it. libstdc++-v3/ChangeLog: PR libstdc++/119671 * include/std/format (__formatter_fp::format): Do not invalidate __wstr unless _M_localized returns a valid string. * testsuite/std/format/functions/format.cc: Check wide string formatting of floating-point types with classic locale. Reviewed-by: Tomasz Kaminski <tkami...@redhat.com> (cherry picked from commit e33b62eed7fd0a82d758b23252d288585b6790d2) Diff: --- libstdc++-v3/include/std/format | 9 +++++---- libstdc++-v3/testsuite/std/format/functions/format.cc | 12 ++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 26e87c427afd..f46012a2b014 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -1669,12 +1669,13 @@ namespace __format if (_M_spec._M_localized && __builtin_isfinite(__v)) { + basic_string<_CharT> __s; if constexpr (is_same_v<char, _CharT>) - __wstr = _M_localize(__str, __expc, __fc.locale()); + __s = _M_localize(__str, __expc, __fc.locale()); else - __wstr = _M_localize(__str, __expc, __loc.value()); - if (!__wstr.empty()) - __str = __wstr; + __s = _M_localize(__str, __expc, __loc.value()); + if (!__s.empty()) + __str = __wstr = std::move(__s); } size_t __width = _M_spec._M_get_width(__fc); diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc index 16f5cda39f16..5d1d9ed07200 100644 --- a/libstdc++-v3/testsuite/std/format/functions/format.cc +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc @@ -349,6 +349,18 @@ test_wchar() // P2909R4 Fix formatting of code units as integers (Dude, where’s my char?) s = std::format(L"{:d} {:d}", wchar_t(-1), char(-1)); VERIFY( s.find('-') == std::wstring::npos ); + + auto ws = std::format(L"{:L}", 0.5); + VERIFY( ws == L"0.5" ); + // The default C locale. + std::locale cloc = std::locale::classic(); + // PR libstdc++/119671 use-after-free formatting floating-point to wstring + ws = std::format(cloc, L"{:L}", 0.5); + VERIFY( ws == L"0.5" ); + // A locale with no name, but with the same facets as the C locale. + std::locale locx(cloc, &std::use_facet<std::ctype<char>>(cloc)); + ws = std::format(locx, L"{:L}", 0.5); + VERIFY( ws == L"0.5" ); } void