On Wed, Nov 26, 2025 at 6:58 PM Jonathan Wakely <[email protected]> wrote:

> My recent changes to support a 64-bit __platform_wait_t for FreeBSD and
> Darwin revealed a problem in std::counting_semaphore. When the default
> template argument is used and __platform_wait_t is a 64-bit type, the
> numeric_limits<__platform_wait_t>::max() value doesn't fit in ptrdiff_t
> and so we get ptrdiff_t(-1), which fails a static_assert in the class
> body.
>
> The solution is to cap the value to PTRDIFF_MAX instead of allowing it
> to go negative.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/semaphore_base.h (__platform_semaphore::_S_max):
>         Limit to PTRDIFF_MAX to avoid negative values.
>         * testsuite/30_threads/semaphore/least_max_value.cc: New test.
> ---
>
LGTM

>
> While benchmarking the atomic wait/notify changes on freebsd I noticed
> that std::counting_semaphore<> no longer compiled.
>
> This didn't show up sooner because until now the only target that
> defined __platform_wait_uses_type<__platform_wait_t> == true was linux
> where __platform_wait_t is int, and INT_MAX <= PTRDIFF_MAX.
>
> Tested x86_64-linux and x86_64-freebsd14.
>
>  libstdc++-v3/include/bits/semaphore_base.h         | 14 ++++++++++++--
>  .../30_threads/semaphore/least_max_value.cc        |  9 +++++++++
>  2 files changed, 21 insertions(+), 2 deletions(-)
>  create mode 100644
> libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.cc
>
> diff --git a/libstdc++-v3/include/bits/semaphore_base.h
> b/libstdc++-v3/include/bits/semaphore_base.h
> index 82871ce3518b..cb815d340aca 100644
> --- a/libstdc++-v3/include/bits/semaphore_base.h
> +++ b/libstdc++-v3/include/bits/semaphore_base.h
> @@ -173,8 +173,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>    {
>      using __count_type = __detail::__platform_wait_t;
>
> -    static constexpr ptrdiff_t _S_max
> -      = _Binary ? 1 : __gnu_cxx::__int_traits<__count_type>::__max;
> +    static consteval ptrdiff_t
> +    _S_calc_max()
> +    {
> +      if (_Binary)
> +       return 1;
> +      else if ((ptrdiff_t)__gnu_cxx::__int_traits<__count_type>::__max <
> 0)
> +       return __gnu_cxx::__int_traits<ptrdiff_t>::__max;
> +      else
> +       return __gnu_cxx::__int_traits<__count_type>::__max;
> +    }
> +
> +    static constexpr ptrdiff_t _S_max = _S_calc_max();
>
>      constexpr explicit
>      __platform_semaphore_impl(__count_type __count) noexcept
> diff --git
> a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.cc
> b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.cc
> new file mode 100644
> index 000000000000..67fa1258b7f0
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.cc
> @@ -0,0 +1,9 @@
> +// { dg-do compile { target c++20 } }
> +// { dg-require-effective-target gthreads { target { ! *-*-linux* } } }
> +// { dg-require-effective-target hosted }
> +
> +#include <semaphore>
> +
> +std::counting_semaphore<> sem(0);
> +std::counting_semaphore<> sem2(2);
> +std::counting_semaphore sem3(3);
> --
> 2.51.1
>
>

Reply via email to