Skip to content

Commit 0f8f6be

Browse files
Fix and improve array and mdspan static analysis warnings (#4856)
1 parent 3edd71e commit 0f8f6be

File tree

17 files changed

+155
-61
lines changed

17 files changed

+155
-61
lines changed

stl/inc/array

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ public:
500500
return _Elems + _Size;
501501
}
502502

503-
_NODISCARD constexpr size_type size() const noexcept {
503+
_NODISCARD _Ret_range_(==, _Size) constexpr size_type size() const noexcept {
504504
return _Size;
505505
}
506506

@@ -528,15 +528,15 @@ public:
528528
return _Elems[_Pos];
529529
}
530530

531-
_NODISCARD _CONSTEXPR17 reference operator[](_In_range_(0, _Size - 1) size_type _Pos) noexcept /* strengthened */ {
531+
_NODISCARD _CONSTEXPR17 reference operator[](_In_range_(<, _Size) size_type _Pos) noexcept /* strengthened */ {
532532
#if _CONTAINER_DEBUG_LEVEL > 0
533533
_STL_VERIFY(_Pos < _Size, "array subscript out of range");
534534
#endif // _CONTAINER_DEBUG_LEVEL > 0
535535

536536
return _Elems[_Pos];
537537
}
538538

539-
_NODISCARD constexpr const_reference operator[](_In_range_(0, _Size - 1) size_type _Pos) const noexcept
539+
_NODISCARD constexpr const_reference operator[](_In_range_(<, _Size) size_type _Pos) const noexcept
540540
/* strengthened */ {
541541
#if _CONTAINER_DEBUG_LEVEL > 0
542542
_STL_VERIFY(_Pos < _Size, "array subscript out of range");

stl/inc/mdspan

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ private:
8181
rank_type _Counter = 0;
8282
for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) {
8383
if (_Static_extents[_Idx] == dynamic_extent) {
84-
_Analysis_assume_(_Counter < _Rank_dynamic); // TRANSITION, DevCom-923103
84+
_Analysis_assume_(_Counter < _Rank_dynamic); // guaranteed by how _Rank_dynamic is calculated
8585
_Result[_Counter] = _Idx;
8686
++_Counter;
8787
}
@@ -174,22 +174,22 @@ private:
174174
}
175175

176176
public:
177-
_NODISCARD static constexpr rank_type rank() noexcept {
177+
_NODISCARD _Ret_range_(==, _Rank) static constexpr rank_type rank() noexcept {
178178
return _Rank;
179179
}
180180

181181
_NODISCARD static constexpr rank_type rank_dynamic() noexcept {
182182
return _Rank_dynamic;
183183
}
184184

185-
_NODISCARD static constexpr size_t static_extent(const rank_type _Idx) noexcept {
185+
_NODISCARD static constexpr size_t static_extent(_In_range_(<, _Rank) const rank_type _Idx) noexcept {
186186
#if _CONTAINER_DEBUG_LEVEL > 0
187187
_STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)");
188188
#endif // _CONTAINER_DEBUG_LEVEL > 0
189189
return _Static_extents[_Idx];
190190
}
191191

192-
_NODISCARD constexpr index_type extent(const rank_type _Idx) const noexcept {
192+
_NODISCARD constexpr index_type extent(_In_range_(<, _Rank) const rank_type _Idx) const noexcept {
193193
#if _CONTAINER_DEBUG_LEVEL > 0
194194
_STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/3)");
195195
#endif // _CONTAINER_DEBUG_LEVEL > 0
@@ -591,7 +591,7 @@ public:
591591
return true;
592592
}
593593

594-
_NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept
594+
_NODISCARD constexpr index_type stride(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept
595595
requires (extents_type::rank() > 0)
596596
{
597597
#if _CONTAINER_DEBUG_LEVEL > 0
@@ -744,7 +744,7 @@ public:
744744
return true;
745745
}
746746

747-
_NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept
747+
_NODISCARD constexpr index_type stride(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept
748748
requires (extents_type::rank() > 0)
749749
{
750750
#if _CONTAINER_DEBUG_LEVEL > 0
@@ -975,10 +975,14 @@ public:
975975
return true;
976976
}
977977

978-
_NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept {
978+
_NODISCARD constexpr index_type stride(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept {
979979
if constexpr (extents_type::rank() == 0) {
980980
_STL_VERIFY(false, "The argument to stride must be nonnegative and less than extents_type::rank().");
981981
} else {
982+
#if _CONTAINER_DEBUG_LEVEL > 0
983+
_STL_VERIFY(_Idx < extents_type::_Rank,
984+
"The argument to stride must be nonnegative and less than extents_type::rank().");
985+
#endif // _CONTAINER_DEBUG_LEVEL > 0
982986
return this->_Array[_Idx];
983987
}
984988
}
@@ -1187,22 +1191,22 @@ private:
11871191
"[mdspan.mdspan.overview]/2.3).");
11881192

11891193
public:
1190-
_NODISCARD static constexpr rank_type rank() noexcept {
1194+
_NODISCARD _Ret_range_(==, extents_type::_Rank) static constexpr rank_type rank() noexcept {
11911195
return extents_type::_Rank;
11921196
}
11931197

11941198
_NODISCARD static constexpr rank_type rank_dynamic() noexcept {
11951199
return extents_type::_Rank_dynamic;
11961200
}
11971201

1198-
_NODISCARD static constexpr size_t static_extent(const rank_type _Idx) noexcept {
1202+
_NODISCARD static constexpr size_t static_extent(_In_range_(<, extents_type::_Rank) const rank_type _Idx) noexcept {
11991203
#if _CONTAINER_DEBUG_LEVEL > 0
12001204
_STL_VERIFY(_Idx < extents_type::_Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)");
12011205
#endif // _CONTAINER_DEBUG_LEVEL > 0
12021206
return extents_type::_Static_extents[_Idx];
12031207
}
12041208

1205-
_NODISCARD constexpr index_type extent(const rank_type _Idx) const noexcept {
1209+
_NODISCARD constexpr index_type extent(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept {
12061210
return this->_Map.extents().extent(_Idx);
12071211
}
12081212

tests/libcxx/expected_results.txt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -992,22 +992,15 @@ std/utilities/format/format.range/format.range.fmtset/format.pass.cpp FAIL
992992
std/utilities/format/format.range/format.range.fmtstr/format.pass.cpp FAIL
993993
std/utilities/format/format.tuple/format.pass.cpp FAIL
994994

995-
# Not analyzed. Apparent false positives from static analysis where it thinks that array indexing is out of bounds.
996-
# warning C28020: The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.
995+
# Not analyzed. Static analysis thinks that array indexing is out of bounds because it can't prove otherwise.
996+
# warning C28020: The expression '_Param_(1)<1' is not true at this call.
997997
# Note: The :1 (ASAN) configuration doesn't run static analysis.
998998
std/containers/views/mdspan/extents/ctor_default.pass.cpp:0 FAIL
999999
std/containers/views/mdspan/extents/ctor_from_array.pass.cpp:0 FAIL
10001000
std/containers/views/mdspan/extents/ctor_from_integral.pass.cpp:0 FAIL
10011001
std/containers/views/mdspan/extents/ctor_from_span.pass.cpp:0 FAIL
1002-
std/containers/views/mdspan/layout_left/ctor.layout_stride.pass.cpp:0 FAIL
1003-
std/containers/views/mdspan/layout_left/stride.pass.cpp:0 FAIL
1004-
std/containers/views/mdspan/layout_right/ctor.layout_stride.pass.cpp:0 FAIL
1005-
std/containers/views/mdspan/layout_right/stride.pass.cpp:0 FAIL
1006-
std/containers/views/mdspan/layout_stride/ctor.default.pass.cpp:0 FAIL
1007-
std/containers/views/mdspan/layout_stride/ctor.extents_array.pass.cpp:0 FAIL
1008-
std/containers/views/mdspan/layout_stride/ctor.extents_span.pass.cpp:0 FAIL
1002+
std/containers/views/mdspan/layout_stride/comparison.pass.cpp:0 FAIL
10091003
std/containers/views/mdspan/layout_stride/ctor.strided_mapping.pass.cpp:0 FAIL
1010-
std/containers/views/mdspan/layout_stride/stride.pass.cpp:0 FAIL
10111004
std/containers/views/mdspan/mdspan/conversion.pass.cpp:0 FAIL
10121005
std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp:0 FAIL
10131006
std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp:0 FAIL
@@ -1086,6 +1079,8 @@ std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.ra
10861079
std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.range.pass.cpp:1 SKIPPED
10871080
std/algorithms/alg.nonmodifying/alg.ends_with/ranges.ends_with.pass.cpp:0 SKIPPED
10881081
std/algorithms/alg.nonmodifying/alg.ends_with/ranges.ends_with.pass.cpp:1 SKIPPED
1082+
std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp:0 SKIPPED
1083+
std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp:1 SKIPPED
10891084
std/algorithms/alg.sorting/alg.merge/ranges_merge.pass.cpp:0 SKIPPED
10901085
std/algorithms/alg.sorting/alg.merge/ranges_merge.pass.cpp:1 SKIPPED
10911086
std/algorithms/alg.sorting/alg.set.operations/includes/ranges_includes.pass.cpp:0 SKIPPED

tests/std/include/test_mdspan_support.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,10 @@ MappingProperties<Mapping> get_mapping_properties(const Mapping& mapping) {
251251
constexpr auto rank = Mapping::extents_type::rank();
252252
constexpr std::make_index_sequence<rank> rank_indices;
253253

254-
auto get_extent = [&](size_t i) { return mapping.extents().extent(i); };
254+
auto get_extent = [&](size_t i) {
255+
assert(i < rank);
256+
return mapping.extents().extent(i);
257+
};
255258
auto multidim_indices = [&]<size_t... Indices>(std::index_sequence<Indices...>) {
256259
return std::views::cartesian_product(std::views::iota(IndexType{0}, get_extent(Indices))...);
257260
}(rank_indices);

tests/std/test.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,4 +758,5 @@ tests\VSO_0849827_multicontainer_emplace_hint_position
758758
tests\VSO_0938757_attribute_order
759759
tests\VSO_0961751_hash_range_erase
760760
tests\VSO_0971246_legacy_await_headers
761+
tests\VSO_1804139_static_analysis_warning_with_single_element_array
761762
tests\VSO_1925201_iter_traits

tests/std/tests/P0009R18_mdspan_extents_death/test.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,19 @@ using namespace std;
1616
void test_static_extent_function_with_invalid_index() {
1717
using E = extents<int, 3>;
1818
// Index must be less than rank()
19+
#pragma warning(push)
20+
#pragma warning(disable : 28020) // yay, /analyze catches this mistake at compile time!
1921
(void) E::static_extent(1);
22+
#pragma warning(pop)
2023
}
2124

2225
void test_extent_function_with_invalid_index() {
2326
extents<int, 3> e;
2427
// Index must be less than rank()
28+
#pragma warning(push)
29+
#pragma warning(disable : 28020) // yay, /analyze catches this mistake at compile time!
2530
(void) e.extent(1);
31+
#pragma warning(pop)
2632
}
2733

2834
void test_construction_from_other_extents_with_invalid_values() {

tests/std/tests/P0009R18_mdspan_layout_left/test.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,7 @@ constexpr void check_members(const extents<IndexType, Extents...>& ext, index_se
9090
if constexpr (Ext::rank() > 0) {
9191
strides.front() = 1;
9292
for (size_t i = 1; i < Ext::rank(); ++i) {
93-
#pragma warning(push)
94-
#pragma warning(disable : 28020) // TRANSITION, DevCom-923103
9593
strides[i] = static_cast<IndexType>(strides[i - 1] * ext.extent(i - 1));
96-
#pragma warning(pop)
9794
}
9895
}
9996

tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ void test_call_operator() {
5959
void test_stride_function() {
6060
layout_left::mapping<extents<int, 3>> m;
6161
// Value of i must be less than extents_type::rank()
62+
#pragma warning(push)
63+
#pragma warning(disable : 28020) // yay, /analyze catches this mistake at compile time!
6264
(void) m.stride(1);
65+
#pragma warning(pop)
6366
}
6467

6568
int main(int argc, char* argv[]) {

tests/std/tests/P0009R18_mdspan_layout_right/test.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,7 @@ constexpr void check_members(const extents<IndexType, Extents...>& ext, index_se
9090
if constexpr (Ext::rank() > 0) {
9191
strides.back() = 1;
9292
for (size_t i = Ext::rank() - 1; i-- > 0;) {
93-
#pragma warning(push)
94-
#pragma warning(disable : 28020) // TRANSITION, DevCom-923103
9593
strides[i] = static_cast<IndexType>(strides[i + 1] * ext.extent(i + 1));
96-
#pragma warning(pop)
9794
}
9895
}
9996

tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ void test_call_operator() {
5959
void test_stride_function() {
6060
layout_right::mapping<extents<int, 3>> m;
6161
// Value of i must be less than extents_type::rank()
62+
#pragma warning(push)
63+
#pragma warning(disable : 28020) // yay, /analyze catches this mistake at compile time!
6264
(void) m.stride(1);
65+
#pragma warning(pop)
6366
}
6467

6568
int main(int argc, char* argv[]) {

0 commit comments

Comments
 (0)