From fec1c8b6a13e5411edebbddc3ad98258f5e282d2 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 19 Nov 2024 17:49:28 +0800 Subject: [PATCH] ``: Fix bogus pointer arithmetic with integer-class (#5091) Co-authored-by: Casey Carter --- stl/inc/algorithm | 49 ++++----- tests/std/include/range_algorithm_support.hpp | 4 +- tests/std/test.lst | 1 + .../env.lst | 4 + .../test.cpp | 99 +++++++++++++++++++ 5 files changed, 133 insertions(+), 24 deletions(-) create mode 100644 tests/std/tests/GH_002885_stable_sort_difference_type/env.lst create mode 100644 tests/std/tests/GH_002885_stable_sort_difference_type/test.cpp diff --git a/stl/inc/algorithm b/stl/inc/algorithm index a0b9a7afe9..5ea4e3db6f 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -6568,7 +6568,9 @@ namespace ranges { if (_Count1 <= _Count2 && _Count1 <= _Capacity) { // buffer left range, then move parts _Uninitialized_backout*> _Backout{ - _Temp_ptr, _RANGES _Uninitialized_move_unchecked(_First, _Mid, _Temp_ptr, _Temp_ptr + _Count1).out}; + _Temp_ptr, _RANGES _Uninitialized_move_unchecked( + _First, _Mid, _Temp_ptr, _Temp_ptr + static_cast(_Count1)) + .out}; const _It _New_mid = _RANGES _Move_unchecked(_STD move(_Mid), _STD move(_Last), _STD move(_First)).out; _RANGES _Move_unchecked(_Backout._First, _Backout._Last, _New_mid); return _New_mid; @@ -6576,7 +6578,9 @@ namespace ranges { if (_Count2 <= _Capacity) { // buffer right range, then move parts _Uninitialized_backout*> _Backout{ - _Temp_ptr, _RANGES _Uninitialized_move_unchecked(_Mid, _Last, _Temp_ptr, _Temp_ptr + _Count2).out}; + _Temp_ptr, _RANGES _Uninitialized_move_unchecked( + _Mid, _Last, _Temp_ptr, _Temp_ptr + static_cast(_Count2)) + .out}; _RANGES _Move_backward_common(_First, _STD move(_Mid), _STD move(_Last)); return _RANGES _Move_unchecked(_Backout._First, _Backout._Last, _STD move(_First)).out; } @@ -8856,8 +8860,10 @@ namespace ranges { const iter_difference_t<_It> _Half_count_ceil = _Count - _Half_count; const _It _Mid = _First + _Half_count_ceil; if (_Half_count_ceil <= _Capacity) { // temp buffer big enough, sort each half using buffer - _Buffered_merge_sort_common(_First, _Mid, _Half_count_ceil, _Temp_ptr, _Pred, _Proj); - _Buffered_merge_sort_common(_Mid, _Last, _Half_count, _Temp_ptr, _Pred, _Proj); + _Buffered_merge_sort_common( + _First, _Mid, static_cast(_Half_count_ceil), _Temp_ptr, _Pred, _Proj); + _Buffered_merge_sort_common( + _Mid, _Last, static_cast(_Half_count), _Temp_ptr, _Pred, _Proj); } else { // temp buffer not big enough, divide and conquer _Stable_sort_common_buffered(_First, _Mid, _Half_count_ceil, _Temp_ptr, _Capacity, _Pred, _Proj); _Stable_sort_common_buffered(_Mid, _Last, _Half_count, _Temp_ptr, _Capacity, _Pred, _Proj); @@ -8869,24 +8875,24 @@ namespace ranges { } template - static void _Buffered_merge_sort_common(const _It _First, const _It _Last, const iter_difference_t<_It> _Count, + static void _Buffered_merge_sort_common(const _It _First, const _It _Last, const ptrdiff_t _Count, iter_value_t<_It>* const _Temp_ptr, _Pr _Pred, _Pj _Proj) { // sort using temp buffer for merges - // pre: _Count <= capacity of buffer at _Temp_ptr; also allows safe narrowing to ptrdiff_t + // pre: _Count <= capacity of buffer at _Temp_ptr _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); _STL_INTERNAL_CHECK(_Last - _First == _Count); _Insertion_sort_isort_max_chunks(_First, _Last, _Count, _Pred, _Proj); // merge adjacent pairs of chunks to and from temp buffer - if (_Count <= _Isort_max<_It>) { + if (_Count <= _ISORT_MAX) { return; } // do the first merge, constructing elements in the temporary buffer _Uninitialized_chunked_merge_common(_First, _Last, _Temp_ptr, _Count, _Pred, _Proj); _Uninitialized_backout*> _Backout{_Temp_ptr, _Temp_ptr + _Count}; - iter_difference_t<_It> _Chunk_size = _Isort_max<_It>; + ptrdiff_t _Chunk_size = _ISORT_MAX; for (;;) { // unconditionally merge elements back into the source buffer _Chunk_size <<= 1; @@ -8902,14 +8908,13 @@ namespace ranges { } template - static void _Insertion_sort_isort_max_chunks( - _It _First, _It _Last, iter_difference_t<_It> _Count, _Pr _Pred, _Pj _Proj) { + static void _Insertion_sort_isort_max_chunks(_It _First, _It _Last, ptrdiff_t _Count, _Pr _Pred, _Pj _Proj) { // insertion sort every chunk of distance _Isort_max<_It> in [_First, _Last) _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); _STL_INTERNAL_CHECK(_RANGES distance(_First, _Last) == _Count); - for (; _Isort_max<_It> < _Count; _Count -= _Isort_max<_It>) { // sort chunks + for (; _ISORT_MAX < _Count; _Count -= _ISORT_MAX) { // sort chunks _First = _RANGES _Insertion_sort_common(_First, _First + _Isort_max<_It>, _Pred, _Proj); } @@ -8918,8 +8923,8 @@ namespace ranges { } template - static void _Uninitialized_chunked_merge_common(_It _First, const _It _Last, iter_value_t<_It>* const _Dest, - iter_difference_t<_It> _Count, _Pr _Pred, _Pj _Proj) { + static void _Uninitialized_chunked_merge_common( + _It _First, const _It _Last, iter_value_t<_It>* const _Dest, ptrdiff_t _Count, _Pr _Pred, _Pj _Proj) { // move to uninitialized merging adjacent chunks of distance _Isort_max<_It> _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); @@ -8928,14 +8933,14 @@ namespace ranges { _Uninitialized_backout*> _Backout{_Dest}; const auto _Backout_end = _Dest + _Count; - while (_Isort_max<_It> < _Count) { - _Count -= _Isort_max<_It>; - const auto _Chunk2 = (_STD min)(_Isort_max<_It>, _Count); + while (_ISORT_MAX < _Count) { + _Count -= _ISORT_MAX; + const auto _Chunk2 = (_STD min)(static_cast(_ISORT_MAX), _Count); _Count -= _Chunk2; auto _Mid1 = _First + _Isort_max<_It>; - auto _Last1 = _Mid1 + _Chunk2; - auto _Last2 = _Backout._Last + _Isort_max<_It> + _Chunk2; + auto _Last1 = _Mid1 + static_cast>(_Chunk2); + auto _Last2 = _Backout._Last + _ISORT_MAX + _Chunk2; _Backout._Last = _Uninitialized_merge_move( _STD move(_First), _STD move(_Mid1), _Last1, _Backout._Last, _Last2, _Pred, _Proj); _First = _STD move(_Last1); @@ -9015,8 +9020,8 @@ namespace ranges { } template - static void _Chunked_merge_common(_It1 _First, const _It1 _Last, _It2 _Dest, - const iter_difference_t<_It1> _Chunk_size, iter_difference_t<_It1> _Count, _Pr _Pred, _Pj _Proj) { + static void _Chunked_merge_common(_It1 _First, const _It1 _Last, _It2 _Dest, const ptrdiff_t _Chunk_size, + ptrdiff_t _Count, _Pr _Pred, _Pj _Proj) { // move merging adjacent chunks of distance _Chunk_size _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It1>); _STL_INTERNAL_STATIC_ASSERT(sortable<_It1, _Pr, _Pj>); @@ -9029,8 +9034,8 @@ namespace ranges { const auto _Right_chunk_size = (_STD min)(_Chunk_size, _Count); _Count -= _Right_chunk_size; - auto _Mid1 = _First + _Chunk_size; - auto _Last1 = _Mid1 + _Right_chunk_size; + auto _Mid1 = _First + static_cast>(_Chunk_size); + auto _Last1 = _Mid1 + static_cast>(_Right_chunk_size); _Dest = _Merge_move_common(_STD move(_First), _STD move(_Mid1), _Last1, _Dest, _Pred, _Proj); _First = _STD move(_Last1); } diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index d4f430bfbb..056b84b298 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -1163,10 +1163,10 @@ namespace test { if constexpr (is_sized) { const auto sz = to_unsigned(static_cast(ranges::distance(r))); return ranges::subrange{ - rediff_iter{r.begin()}, rediff_sent{r.end()}, sz}; + rediff_iter{ranges::begin(r)}, rediff_sent{ranges::end(r)}, sz}; } else { return ranges::subrange{ - rediff_iter{r.begin()}, rediff_sent{r.end()}}; + rediff_iter{ranges::begin(r)}, rediff_sent{ranges::end(r)}}; } } } // namespace test diff --git a/tests/std/test.lst b/tests/std/test.lst index 94f80f9dce..42163db997 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -221,6 +221,7 @@ tests\GH_002711_Zc_alignedNew- tests\GH_002760_syncstream_memory_leak tests\GH_002769_handle_deque_block_pointers tests\GH_002789_Hash_vec_Tidy +tests\GH_002885_stable_sort_difference_type tests\GH_002989_nothrow_unwrappable tests\GH_002992_unwrappable_iter_sent_pairs tests\GH_003003_format_decimal_point diff --git a/tests/std/tests/GH_002885_stable_sort_difference_type/env.lst b/tests/std/tests/GH_002885_stable_sort_difference_type/env.lst new file mode 100644 index 0000000000..351a8293d9 --- /dev/null +++ b/tests/std/tests/GH_002885_stable_sort_difference_type/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_20_matrix.lst diff --git a/tests/std/tests/GH_002885_stable_sort_difference_type/test.cpp b/tests/std/tests/GH_002885_stable_sort_difference_type/test.cpp new file mode 100644 index 0000000000..34fe497513 --- /dev/null +++ b/tests/std/tests/GH_002885_stable_sort_difference_type/test.cpp @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include "range_algorithm_support.hpp" + +using namespace std; + +constexpr auto pred = [](int i) { return i <= 42; }; + +template +void test_iota_transform() { + constexpr int orig[]{42, 1729}; + int a[]{42, 1729}; + auto vw = views::iota(I{}, static_cast(ranges::size(a))) + | views::transform([&a](I i) -> auto& { return a[static_cast(i)]; }); + + static_assert(three_way_comparable>>); // TRANSITION, /permissive + + ranges::stable_sort(vw); + assert(ranges::equal(a, orig)); + + ranges::stable_sort(vw.begin(), vw.end()); + assert(ranges::equal(a, orig)); + + ranges::inplace_merge(vw, ranges::next(vw.begin())); + assert(ranges::equal(a, orig)); + ranges::inplace_merge(vw.begin(), ranges::next(vw.begin()), vw.end()); + assert(ranges::equal(a, orig)); + + ranges::stable_partition(vw, pred); + assert(ranges::equal(a, orig)); + ranges::stable_partition(vw.begin(), vw.end(), pred); + assert(ranges::equal(a, orig)); +} + +void test_iota_transform_all() { + test_iota_transform(); + test_iota_transform(); + test_iota_transform(); + test_iota_transform(); + test_iota_transform(); + + test_iota_transform(); + test_iota_transform(); + test_iota_transform(); + test_iota_transform(); + test_iota_transform(); + + test_iota_transform(); +#ifdef __cpp_char8_t + test_iota_transform(); +#endif // defined(__cpp_char8_t) + test_iota_transform(); + test_iota_transform(); + test_iota_transform(); +} + +template +void test_redifference() { + constexpr int orig[]{42, 1729}; + int a[]{42, 1729}; + auto vw = test::make_redifference_subrange(a); + + ranges::stable_sort(vw); + assert(ranges::equal(a, orig)); + + ranges::stable_sort(vw.begin(), vw.end()); + assert(ranges::equal(a, orig)); + + ranges::inplace_merge(vw, ranges::next(vw.begin())); + assert(ranges::equal(a, orig)); + ranges::inplace_merge(vw.begin(), ranges::next(vw.begin()), vw.end()); + assert(ranges::equal(a, orig)); + + ranges::stable_partition(vw, pred); + assert(ranges::equal(a, orig)); + ranges::stable_partition(vw.begin(), vw.end(), pred); + assert(ranges::equal(a, orig)); +} + +void test_redifference_all() { + test_redifference(); + test_redifference(); + test_redifference(); + test_redifference(); + test_redifference(); + test_redifference<_Signed128>(); +} + +int main() { + test_iota_transform_all(); + test_redifference_all(); +}