]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix use-after-free in std::format [PR119671]
authorJonathan Wakely <jwakely@redhat.com>
Mon, 7 Apr 2025 18:52:55 +0000 (19:52 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 8 Apr 2025 09:13:39 +0000 (10:13 +0100)
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 <tkaminsk@redhat.com>
(cherry picked from commit e33b62eed7fd0a82d758b23252d288585b6790d2)

libstdc++-v3/include/std/format
libstdc++-v3/testsuite/std/format/functions/format.cc

index 15bded87c9cdfc0b168a8aecb5434139aeb9e9b7..b8830766f40fd9c36f50692f3d044f9209546b54 100644 (file)
@@ -1751,9 +1751,9 @@ namespace __format
 
          if (_M_spec._M_localized && __builtin_isfinite(__v))
            {
-             __wstr = _M_localize(__str, __expc, __fc.locale());
-             if (!__wstr.empty())
-               __str = __wstr;
+             auto __s = _M_localize(__str, __expc, __fc.locale());
+             if (!__s.empty())
+               __str = __wstr = std::move(__s);
            }
 
          size_t __width = _M_spec._M_get_width(__fc);
index 78010e159d366f3344790e33cd947ddaaca3335f..d6575dabb6bcf22fd88b30d4e12ff2804e9559eb 100644 (file)
@@ -366,6 +366,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