https://gcc.gnu.org/g:630c1bfbb5bc3ba9fafca5e97096263ab8f0a04b
commit r16-6246-g630c1bfbb5bc3ba9fafca5e97096263ab8f0a04b Author: Jonathan Wakely <[email protected]> Date: Thu Dec 18 10:38:31 2025 +0000 libstdc++: Fix ranges::stable_sort handling of null buffer [PR123180] 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. Reviewed-by: Patrick Palka <[email protected]> Diff: --- libstdc++-v3/include/bits/ranges_algo.h | 4 +- .../testsuite/25_algorithms/stable_sort/123180.cc | 66 ++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) 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(); +}
