On Thu, 18 Dec 2025, Jonathan Wakely wrote:

> The logic of the null pointer check got reversed when converting the
> std::stable_sort code for ranges::stable_sort.
> 
> libstdc++-v3/ChangeLog:
> 
>       PR libstdc++/123180
>       * include/bits/ranges_algo.h (__stable_sort_fn::operator()): Fix
>       sense of null check. Replace typedef with alias-declaration.
>       * testsuite/25_algorithms/stable_sort/123180.cc: New test.

Oops, I messed up converting the __builtin_expect to an [[unlikely]]..
I double checked the other __builtin_expect conversions (namely in
__inplace_merge) and they look correct at least.  LGTM

> ---
> 
> Tested x86_64-linux.
> 
>  libstdc++-v3/include/bits/ranges_algo.h       |  4 +-
>  .../25_algorithms/stable_sort/123180.cc       | 66 +++++++++++++++++++
>  2 files changed, 68 insertions(+), 2 deletions(-)
>  create mode 100644 libstdc++-v3/testsuite/25_algorithms/stable_sort/123180.cc
> 
> diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
> b/libstdc++-v3/include/bits/ranges_algo.h
> index 5c9fe627aee0..92e298633cf4 100644
> --- a/libstdc++-v3/include/bits/ranges_algo.h
> +++ b/libstdc++-v3/include/bits/ranges_algo.h
> @@ -2709,7 +2709,7 @@ namespace ranges
>           }
>  # endif
>  
> -         typedef _Temporary_buffer<_Iter, iter_value_t<_Iter>> _TmpBuf;
> +         using _TmpBuf = _Temporary_buffer<_Iter, iter_value_t<_Iter>>;
>           // __stable_sort_adaptive sorts the range in two halves,
>           // so the buffer only needs to fit half the range at once.
>           _TmpBuf __buf(__first, ptrdiff_t((__last - __first + 1) / 2));
> @@ -2718,7 +2718,7 @@ namespace ranges
>             __detail::__stable_sort_adaptive(__first,
>                                              __first + 
> _DistanceType(__buf.size()),
>                                              __last, __buf.begin(), 
> __comp_proj);
> -         else if (__buf.begin()) [[unlikely]]
> +         else if (__buf.begin() == nullptr) [[unlikely]]
>             __detail::__inplace_stable_sort(__first, __last, __comp_proj);
>           else
>             __detail::__stable_sort_adaptive_resize(__first, __last, 
> __buf.begin(),
> diff --git a/libstdc++-v3/testsuite/25_algorithms/stable_sort/123180.cc 
> b/libstdc++-v3/testsuite/25_algorithms/stable_sort/123180.cc
> new file mode 100644
> index 000000000000..7c56f37142e0
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/25_algorithms/stable_sort/123180.cc
> @@ -0,0 +1,66 @@
> +// { dg-do run }
> +
> +#include <algorithm>
> +#include <new>
> +#include <cstdlib>
> +#include <cstdio>
> +
> +#if __cplusplus < 201103L
> +# define NOEXCEPT throw()
> +# define nullptr 0
> +# define THROW_BAD_ALLOC throw(std::bad_alloc)
> +#else
> +# define NOEXCEPT noexcept
> +# define THROW_BAD_ALLOC noexcept(false)
> +#endif
> +
> +std::size_t limit = -1u;
> +
> +void* operator new(std::size_t n, const std::nothrow_t&) NOEXCEPT
> +{
> +  if (n > limit)
> +    return NULL;
> +  return std::malloc(n);
> +}
> +
> +void* operator new(std::size_t n) THROW_BAD_ALLOC
> +{
> +  return std::malloc(n);
> +}
> +
> +void operator delete(void* p) NOEXCEPT { std::free(p); }
> +#ifdef __cpp_sized_deallocation
> +void operator delete(void* p, std::size_t) NOEXCEPT { std::free(p); }
> +#endif
> +
> +void
> +test_stl_algo()
> +{
> +  int a[] = { 4, 6, 2, 1, 7, 9, 2, 2, 2, 8 };
> +  limit = -1u;
> +  std::stable_sort(a, a+10); // gets as much memory as it needs
> +  limit = 2 * sizeof(int);
> +  std::stable_sort(a, a+10); // only gets memory for two ints
> +  limit = 0;
> +  std::stable_sort(a, a+10); // gets no memory
> +}
> +
> +void
> +test_ranges_algo()
> +{
> +#if __cplusplus >= 202002L
> +  int a[] = { 4, 6, 2, 1, 7, 9, 2, 2, 2, 8 };
> +  limit = -1u;
> +  std::ranges::stable_sort(a); // gets as much memory as it needs
> +  limit = 2 * sizeof(int);
> +  std::ranges::stable_sort(a); // only gets memory for two ints
> +  limit = 0;
> +  std::ranges::stable_sort(a); // gets no memory
> +#endif
> +}
> +
> +int main()
> +{
> +  test_stl_algo();
> +  test_ranges_algo();
> +}
> -- 
> 2.52.0
> 
> 

Reply via email to