On Thu, 11 May 2023 at 17:04, Patrick Palka <ppa...@redhat.com> wrote:

> On Fri, 5 May 2023, Jonathan Wakely wrote:
>
> >
> >
> > On Fri, 5 May 2023 at 10:43, Florian Weimer wrote:
> >       * Jonathan Wakely via Libstdc:
> >
> >       > We could use strtod for a single-threaded target (i.e.
> >       > !defined(_GLIBCXX_HAS_GTHREADS) by changing the global locale
> using
> >       > setlocale, instead of changing the per-thread locale using
> uselocale.
> >
> >       This is not generally safe because the call to setlocale is still
> >       observable to applications in principle because a previous pointer
> >       returned from setlocale they have store could be invalidated.
> >
> >
> > Ah yes, good point, thanks. I think that's a non-starter then. I still
> think using RAII makes the from_chars_impl function easier to read, so
> here's a version of that patch without the single-threaded
> > conditions.
> >
> > commit 4dc5b8864ec527e699d35880fbc706157113f92b
> > Author: Jonathan Wakely <jwak...@redhat.com>
> > Date:   Thu May 4 15:22:07 2023
> >
> >     libstdc++: Use RAII types in strtod-based std::from_chars
> implementation
> >
> >     This adds auto_locale and auto_ferounding types to use RAII for
> changing
> >     and restoring the local and floating-point environment when using
> strtod
> >     to implement std::from_chars.
> >
> >     The destructors for the RAII objects run slightly later than the
> >     previous statements that restored the locale/fenv, but the
> differences
> >     are just some trivial assignments and an isinf call.
> >
> >     libstdc++-v3/ChangeLog:
> >
> >             * src/c++17/floating_from_chars.cc
> [USE_STRTOD_FOR_FROM_CHARS]
> >             (auto_locale, auto_ferounding): New class types.
> >             (from_chars_impl): Use auto_locale and auto_ferounding.
> >
> > diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc
> b/libstdc++-v3/src/c++17/floating_from_chars.cc
> > index 78b9d92cdc0..7b3bdf445e3 100644
> > --- a/libstdc++-v3/src/c++17/floating_from_chars.cc
> > +++ b/libstdc++-v3/src/c++17/floating_from_chars.cc
> > @@ -597,6 +597,69 @@ namespace
> >      return buf.c_str();
> >    }
> >
> > +  // RAII type to change and restore the locale.
> > +  struct auto_locale
> > +  {
> > +#if _GLIBCXX_HAVE_USELOCALE
> > +    // When we have uselocale we can change the current thread's locale.
> > +    locale_t loc;
> > +    locale_t orig;
>
> It's not a big deal, but we could consider making these members const
> too, like in auto_ferounding.
>

Done for loc, but not for orig (which is currently init'd in the ctor body).


>
> LGTM.  I noticed sprintf_ld from floating_to_chars.cc could benefit from
> auto_ferounding as well.
>

Ah yes. Maybe we should share the class, so we don't have two different
types with internal linkage, and two RTTI definitions etc.

For now I'll just push this patch, and make a note to reuse auto_ferounding
in the other file later.

Thanks for the review.



>
> > +
> > +    auto_locale()
> > +    : loc(::newlocale(LC_ALL_MASK, "C", (locale_t)0))
> > +    {
> > +      if (loc)
> > +     orig = ::uselocale(loc);
> > +      else
> > +     ec = errc{errno};
> > +    }
> > +
> > +    ~auto_locale()
> > +    {
> > +      if (loc)
> > +     {
> > +       ::uselocale(orig);
> > +       ::freelocale(loc);
> > +     }
> > +    }
> > +#else
> > +    // Otherwise, we can't change the locale and so strtod can't be
> used.
> > +    auto_locale() = delete;
> > +#endif
> > +
> > +    explicit operator bool() const noexcept { return ec == errc{}; }
> > +
> > +    errc ec{};
> > +
> > +    auto_locale(const auto_locale&) = delete;
> > +    auto_locale& operator=(const auto_locale&) = delete;
> > +  };
> > +
> > +  // RAII type to change and restore the floating-point environment.
> > +  struct auto_ferounding
> > +  {
> > +#if _GLIBCXX_USE_C99_FENV_TR1 && defined(FE_TONEAREST)
> > +    const int rounding = std::fegetround();
> > +
> > +    auto_ferounding()
> > +    {
> > +      if (rounding != FE_TONEAREST)
> > +     std::fesetround(FE_TONEAREST);
> > +    }
> > +
> > +    ~auto_ferounding()
> > +    {
> > +      if (rounding != FE_TONEAREST)
> > +     std::fesetround(rounding);
> > +    }
> > +#else
> > +    auto_ferounding() = default;
> > +#endif
> > +
> > +    auto_ferounding(const auto_ferounding&) = delete;
> > +    auto_ferounding& operator=(const auto_ferounding&) = delete;
> > +  };
> > +
> >    // Convert the NTBS `str` to a floating-point value of type `T`.
> >    // If `str` cannot be converted, `value` is unchanged and `0` is
> returned.
> >    // Otherwise, let N be the number of characters consumed from `str`.
> > @@ -607,16 +670,11 @@ namespace
> >    ptrdiff_t
> >    from_chars_impl(const char* str, T& value, errc& ec) noexcept
> >    {
> > -    if (locale_t loc = ::newlocale(LC_ALL_MASK, "C", (locale_t)0))
> [[likely]]
> > +    auto_locale loc;
> > +
> > +    if (loc)
> >        {
> > -     locale_t orig = ::uselocale(loc);
> > -
> > -#if _GLIBCXX_USE_C99_FENV_TR1 && defined(FE_TONEAREST)
> > -     const int rounding = std::fegetround();
> > -     if (rounding != FE_TONEAREST)
> > -       std::fesetround(FE_TONEAREST);
> > -#endif
> > -
> > +     auto_ferounding rounding;
> >       const int save_errno = errno;
> >       errno = 0;
> >       char* endptr;
> > @@ -647,14 +705,6 @@ namespace
> >  #endif
> >       const int conv_errno = std::__exchange(errno, save_errno);
> >
> > -#if _GLIBCXX_USE_C99_FENV_TR1 && defined(FE_TONEAREST)
> > -     if (rounding != FE_TONEAREST)
> > -       std::fesetround(rounding);
> > -#endif
> > -
> > -     ::uselocale(orig);
> > -     ::freelocale(loc);
> > -
> >       const ptrdiff_t n = endptr - str;
> >       if (conv_errno == ERANGE) [[unlikely]]
> >         {
> > @@ -675,8 +725,8 @@ namespace
> >         }
> >       return n;
> >        }
> > -    else if (errno == ENOMEM)
> > -      ec = errc::not_enough_memory;
> > +    else
> > +      ec = loc.ec;
> >
> >      return 0;
> >    }
>
>

Reply via email to