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

Reply via email to