On Tue, Apr 8, 2025 at 1:25 AM Jonathan Wakely <jwak...@redhat.com> wrote:
> 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. > --- > > Tested x86_64-linux. > LGTM. > > libstdc++-v3/include/std/format | 6 +++--- > .../testsuite/std/format/functions/format.cc | 12 ++++++++++++ > 2 files changed, 15 insertions(+), 3 deletions(-) > > diff --git a/libstdc++-v3/include/std/format > b/libstdc++-v3/include/std/format > index 01a53143d1c..2e9319cdda6 100644 > --- a/libstdc++-v3/include/std/format > +++ b/libstdc++-v3/include/std/format > @@ -1838,9 +1838,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); > diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc > b/libstdc++-v3/testsuite/std/format/functions/format.cc > index 000f2671816..93c33b456e6 100644 > --- a/libstdc++-v3/testsuite/std/format/functions/format.cc > +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc > @@ -370,6 +370,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 > -- > 2.49.0 > >