Skip to content

Commit fec1c8b

Browse files
<algorithm>: Fix bogus pointer arithmetic with integer-class (#5091)
Co-authored-by: Casey Carter <[email protected]>
1 parent 1711bc3 commit fec1c8b

File tree

5 files changed

+133
-24
lines changed

5 files changed

+133
-24
lines changed

stl/inc/algorithm

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6568,15 +6568,19 @@ namespace ranges {
65686568

65696569
if (_Count1 <= _Count2 && _Count1 <= _Capacity) { // buffer left range, then move parts
65706570
_Uninitialized_backout<iter_value_t<_It>*> _Backout{
6571-
_Temp_ptr, _RANGES _Uninitialized_move_unchecked(_First, _Mid, _Temp_ptr, _Temp_ptr + _Count1).out};
6571+
_Temp_ptr, _RANGES _Uninitialized_move_unchecked(
6572+
_First, _Mid, _Temp_ptr, _Temp_ptr + static_cast<ptrdiff_t>(_Count1))
6573+
.out};
65726574
const _It _New_mid = _RANGES _Move_unchecked(_STD move(_Mid), _STD move(_Last), _STD move(_First)).out;
65736575
_RANGES _Move_unchecked(_Backout._First, _Backout._Last, _New_mid);
65746576
return _New_mid;
65756577
}
65766578

65776579
if (_Count2 <= _Capacity) { // buffer right range, then move parts
65786580
_Uninitialized_backout<iter_value_t<_It>*> _Backout{
6579-
_Temp_ptr, _RANGES _Uninitialized_move_unchecked(_Mid, _Last, _Temp_ptr, _Temp_ptr + _Count2).out};
6581+
_Temp_ptr, _RANGES _Uninitialized_move_unchecked(
6582+
_Mid, _Last, _Temp_ptr, _Temp_ptr + static_cast<ptrdiff_t>(_Count2))
6583+
.out};
65806584
_RANGES _Move_backward_common(_First, _STD move(_Mid), _STD move(_Last));
65816585
return _RANGES _Move_unchecked(_Backout._First, _Backout._Last, _STD move(_First)).out;
65826586
}
@@ -8856,8 +8860,10 @@ namespace ranges {
88568860
const iter_difference_t<_It> _Half_count_ceil = _Count - _Half_count;
88578861
const _It _Mid = _First + _Half_count_ceil;
88588862
if (_Half_count_ceil <= _Capacity) { // temp buffer big enough, sort each half using buffer
8859-
_Buffered_merge_sort_common(_First, _Mid, _Half_count_ceil, _Temp_ptr, _Pred, _Proj);
8860-
_Buffered_merge_sort_common(_Mid, _Last, _Half_count, _Temp_ptr, _Pred, _Proj);
8863+
_Buffered_merge_sort_common(
8864+
_First, _Mid, static_cast<ptrdiff_t>(_Half_count_ceil), _Temp_ptr, _Pred, _Proj);
8865+
_Buffered_merge_sort_common(
8866+
_Mid, _Last, static_cast<ptrdiff_t>(_Half_count), _Temp_ptr, _Pred, _Proj);
88618867
} else { // temp buffer not big enough, divide and conquer
88628868
_Stable_sort_common_buffered(_First, _Mid, _Half_count_ceil, _Temp_ptr, _Capacity, _Pred, _Proj);
88638869
_Stable_sort_common_buffered(_Mid, _Last, _Half_count, _Temp_ptr, _Capacity, _Pred, _Proj);
@@ -8869,24 +8875,24 @@ namespace ranges {
88698875
}
88708876

88718877
template <class _It, class _Pr, class _Pj>
8872-
static void _Buffered_merge_sort_common(const _It _First, const _It _Last, const iter_difference_t<_It> _Count,
8878+
static void _Buffered_merge_sort_common(const _It _First, const _It _Last, const ptrdiff_t _Count,
88738879
iter_value_t<_It>* const _Temp_ptr, _Pr _Pred, _Pj _Proj) {
88748880
// sort using temp buffer for merges
8875-
// pre: _Count <= capacity of buffer at _Temp_ptr; also allows safe narrowing to ptrdiff_t
8881+
// pre: _Count <= capacity of buffer at _Temp_ptr
88768882
_STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>);
88778883
_STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>);
88788884
_STL_INTERNAL_CHECK(_Last - _First == _Count);
88798885

88808886
_Insertion_sort_isort_max_chunks(_First, _Last, _Count, _Pred, _Proj);
88818887
// merge adjacent pairs of chunks to and from temp buffer
8882-
if (_Count <= _Isort_max<_It>) {
8888+
if (_Count <= _ISORT_MAX) {
88838889
return;
88848890
}
88858891

88868892
// do the first merge, constructing elements in the temporary buffer
88878893
_Uninitialized_chunked_merge_common(_First, _Last, _Temp_ptr, _Count, _Pred, _Proj);
88888894
_Uninitialized_backout<iter_value_t<_It>*> _Backout{_Temp_ptr, _Temp_ptr + _Count};
8889-
iter_difference_t<_It> _Chunk_size = _Isort_max<_It>;
8895+
ptrdiff_t _Chunk_size = _ISORT_MAX;
88908896
for (;;) {
88918897
// unconditionally merge elements back into the source buffer
88928898
_Chunk_size <<= 1;
@@ -8902,14 +8908,13 @@ namespace ranges {
89028908
}
89038909

89048910
template <class _It, class _Pr, class _Pj>
8905-
static void _Insertion_sort_isort_max_chunks(
8906-
_It _First, _It _Last, iter_difference_t<_It> _Count, _Pr _Pred, _Pj _Proj) {
8911+
static void _Insertion_sort_isort_max_chunks(_It _First, _It _Last, ptrdiff_t _Count, _Pr _Pred, _Pj _Proj) {
89078912
// insertion sort every chunk of distance _Isort_max<_It> in [_First, _Last)
89088913
_STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>);
89098914
_STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>);
89108915
_STL_INTERNAL_CHECK(_RANGES distance(_First, _Last) == _Count);
89118916

8912-
for (; _Isort_max<_It> < _Count; _Count -= _Isort_max<_It>) { // sort chunks
8917+
for (; _ISORT_MAX < _Count; _Count -= _ISORT_MAX) { // sort chunks
89138918
_First = _RANGES _Insertion_sort_common(_First, _First + _Isort_max<_It>, _Pred, _Proj);
89148919
}
89158920

@@ -8918,8 +8923,8 @@ namespace ranges {
89188923
}
89198924

89208925
template <class _It, class _Pr, class _Pj>
8921-
static void _Uninitialized_chunked_merge_common(_It _First, const _It _Last, iter_value_t<_It>* const _Dest,
8922-
iter_difference_t<_It> _Count, _Pr _Pred, _Pj _Proj) {
8926+
static void _Uninitialized_chunked_merge_common(
8927+
_It _First, const _It _Last, iter_value_t<_It>* const _Dest, ptrdiff_t _Count, _Pr _Pred, _Pj _Proj) {
89238928
// move to uninitialized merging adjacent chunks of distance _Isort_max<_It>
89248929
_STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>);
89258930
_STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>);
@@ -8928,14 +8933,14 @@ namespace ranges {
89288933

89298934
_Uninitialized_backout<iter_value_t<_It>*> _Backout{_Dest};
89308935
const auto _Backout_end = _Dest + _Count;
8931-
while (_Isort_max<_It> < _Count) {
8932-
_Count -= _Isort_max<_It>;
8933-
const auto _Chunk2 = (_STD min)(_Isort_max<_It>, _Count);
8936+
while (_ISORT_MAX < _Count) {
8937+
_Count -= _ISORT_MAX;
8938+
const auto _Chunk2 = (_STD min)(static_cast<ptrdiff_t>(_ISORT_MAX), _Count);
89348939
_Count -= _Chunk2;
89358940

89368941
auto _Mid1 = _First + _Isort_max<_It>;
8937-
auto _Last1 = _Mid1 + _Chunk2;
8938-
auto _Last2 = _Backout._Last + _Isort_max<_It> + _Chunk2;
8942+
auto _Last1 = _Mid1 + static_cast<iter_difference_t<_It>>(_Chunk2);
8943+
auto _Last2 = _Backout._Last + _ISORT_MAX + _Chunk2;
89398944
_Backout._Last = _Uninitialized_merge_move(
89408945
_STD move(_First), _STD move(_Mid1), _Last1, _Backout._Last, _Last2, _Pred, _Proj);
89418946
_First = _STD move(_Last1);
@@ -9015,8 +9020,8 @@ namespace ranges {
90159020
}
90169021

90179022
template <class _It1, class _It2, class _Pr, class _Pj>
9018-
static void _Chunked_merge_common(_It1 _First, const _It1 _Last, _It2 _Dest,
9019-
const iter_difference_t<_It1> _Chunk_size, iter_difference_t<_It1> _Count, _Pr _Pred, _Pj _Proj) {
9023+
static void _Chunked_merge_common(_It1 _First, const _It1 _Last, _It2 _Dest, const ptrdiff_t _Chunk_size,
9024+
ptrdiff_t _Count, _Pr _Pred, _Pj _Proj) {
90209025
// move merging adjacent chunks of distance _Chunk_size
90219026
_STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It1>);
90229027
_STL_INTERNAL_STATIC_ASSERT(sortable<_It1, _Pr, _Pj>);
@@ -9029,8 +9034,8 @@ namespace ranges {
90299034
const auto _Right_chunk_size = (_STD min)(_Chunk_size, _Count);
90309035
_Count -= _Right_chunk_size;
90319036

9032-
auto _Mid1 = _First + _Chunk_size;
9033-
auto _Last1 = _Mid1 + _Right_chunk_size;
9037+
auto _Mid1 = _First + static_cast<iter_difference_t<_It1>>(_Chunk_size);
9038+
auto _Last1 = _Mid1 + static_cast<iter_difference_t<_It1>>(_Right_chunk_size);
90349039
_Dest = _Merge_move_common(_STD move(_First), _STD move(_Mid1), _Last1, _Dest, _Pred, _Proj);
90359040
_First = _STD move(_Last1);
90369041
}

tests/std/include/range_algorithm_support.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,10 +1163,10 @@ namespace test {
11631163
if constexpr (is_sized) {
11641164
const auto sz = to_unsigned(static_cast<Diff>(ranges::distance(r)));
11651165
return ranges::subrange<rediff_iter, rediff_sent, ranges::subrange_kind::sized>{
1166-
rediff_iter{r.begin()}, rediff_sent{r.end()}, sz};
1166+
rediff_iter{ranges::begin(r)}, rediff_sent{ranges::end(r)}, sz};
11671167
} else {
11681168
return ranges::subrange<rediff_iter, rediff_sent, ranges::subrange_kind::unsized>{
1169-
rediff_iter{r.begin()}, rediff_sent{r.end()}};
1169+
rediff_iter{ranges::begin(r)}, rediff_sent{ranges::end(r)}};
11701170
}
11711171
}
11721172
} // namespace test

tests/std/test.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ tests\GH_002711_Zc_alignedNew-
221221
tests\GH_002760_syncstream_memory_leak
222222
tests\GH_002769_handle_deque_block_pointers
223223
tests\GH_002789_Hash_vec_Tidy
224+
tests\GH_002885_stable_sort_difference_type
224225
tests\GH_002989_nothrow_unwrappable
225226
tests\GH_002992_unwrappable_iter_sent_pairs
226227
tests\GH_003003_format_decimal_point
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\usual_20_matrix.lst
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#include <algorithm>
5+
#include <cassert>
6+
#include <cstddef>
7+
#include <cstdint>
8+
#include <ranges>
9+
10+
#include "range_algorithm_support.hpp"
11+
12+
using namespace std;
13+
14+
constexpr auto pred = [](int i) { return i <= 42; };
15+
16+
template <class I>
17+
void test_iota_transform() {
18+
constexpr int orig[]{42, 1729};
19+
int a[]{42, 1729};
20+
auto vw = views::iota(I{}, static_cast<I>(ranges::size(a)))
21+
| views::transform([&a](I i) -> auto& { return a[static_cast<size_t>(i)]; });
22+
23+
static_assert(three_way_comparable<ranges::iterator_t<ranges::iota_view<I>>>); // TRANSITION, /permissive
24+
25+
ranges::stable_sort(vw);
26+
assert(ranges::equal(a, orig));
27+
28+
ranges::stable_sort(vw.begin(), vw.end());
29+
assert(ranges::equal(a, orig));
30+
31+
ranges::inplace_merge(vw, ranges::next(vw.begin()));
32+
assert(ranges::equal(a, orig));
33+
ranges::inplace_merge(vw.begin(), ranges::next(vw.begin()), vw.end());
34+
assert(ranges::equal(a, orig));
35+
36+
ranges::stable_partition(vw, pred);
37+
assert(ranges::equal(a, orig));
38+
ranges::stable_partition(vw.begin(), vw.end(), pred);
39+
assert(ranges::equal(a, orig));
40+
}
41+
42+
void test_iota_transform_all() {
43+
test_iota_transform<signed char>();
44+
test_iota_transform<short>();
45+
test_iota_transform<int>();
46+
test_iota_transform<long>();
47+
test_iota_transform<long long>();
48+
49+
test_iota_transform<unsigned char>();
50+
test_iota_transform<unsigned short>();
51+
test_iota_transform<unsigned int>();
52+
test_iota_transform<unsigned long>();
53+
test_iota_transform<unsigned long long>();
54+
55+
test_iota_transform<char>();
56+
#ifdef __cpp_char8_t
57+
test_iota_transform<char8_t>();
58+
#endif // defined(__cpp_char8_t)
59+
test_iota_transform<char16_t>();
60+
test_iota_transform<char32_t>();
61+
test_iota_transform<wchar_t>();
62+
}
63+
64+
template <class I>
65+
void test_redifference() {
66+
constexpr int orig[]{42, 1729};
67+
int a[]{42, 1729};
68+
auto vw = test::make_redifference_subrange<I>(a);
69+
70+
ranges::stable_sort(vw);
71+
assert(ranges::equal(a, orig));
72+
73+
ranges::stable_sort(vw.begin(), vw.end());
74+
assert(ranges::equal(a, orig));
75+
76+
ranges::inplace_merge(vw, ranges::next(vw.begin()));
77+
assert(ranges::equal(a, orig));
78+
ranges::inplace_merge(vw.begin(), ranges::next(vw.begin()), vw.end());
79+
assert(ranges::equal(a, orig));
80+
81+
ranges::stable_partition(vw, pred);
82+
assert(ranges::equal(a, orig));
83+
ranges::stable_partition(vw.begin(), vw.end(), pred);
84+
assert(ranges::equal(a, orig));
85+
}
86+
87+
void test_redifference_all() {
88+
test_redifference<signed char>();
89+
test_redifference<short>();
90+
test_redifference<int>();
91+
test_redifference<long>();
92+
test_redifference<long long>();
93+
test_redifference<_Signed128>();
94+
}
95+
96+
int main() {
97+
test_iota_transform_all();
98+
test_redifference_all();
99+
}

0 commit comments

Comments
 (0)