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
>
>

Reply via email to