Skip to content

Commit 4c4606a

Browse files
authored
[libc++] Add missing assertion in std::span constructor (#118396)
The (iterator, size) constructor should ensure that it gets passed a valid range when the size is not 0. Fixes #107789
1 parent 1094641 commit 4c4606a

File tree

2 files changed

+47
-7
lines changed

2 files changed

+47
-7
lines changed

libcxx/include/span

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ public:
267267
_LIBCPP_HIDE_FROM_ABI constexpr explicit span(_It __first, size_type __count) : __data_{std::to_address(__first)} {
268268
(void)__count;
269269
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Extent == __count, "size mismatch in span's constructor (iterator, len)");
270+
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__count == 0 || std::to_address(__first) != nullptr,
271+
"passed nullptr with non-zero length in span's constructor (iterator, len)");
270272
}
271273

272274
template <__span_compatible_iterator<element_type> _It, __span_compatible_sentinel_for<_It> _End>
@@ -441,7 +443,10 @@ public:
441443

442444
template <__span_compatible_iterator<element_type> _It>
443445
_LIBCPP_HIDE_FROM_ABI constexpr span(_It __first, size_type __count)
444-
: __data_{std::to_address(__first)}, __size_{__count} {}
446+
: __data_{std::to_address(__first)}, __size_{__count} {
447+
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__count == 0 || std::to_address(__first) != nullptr,
448+
"passed nullptr with non-zero length in span's constructor (iterator, len)");
449+
}
445450

446451
template <__span_compatible_iterator<element_type> _It, __span_compatible_sentinel_for<_It> _End>
447452
_LIBCPP_HIDE_FROM_ABI constexpr span(_It __first, _End __last)

libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,48 @@
2525
#include "check_assertion.h"
2626

2727
int main(int, char**) {
28-
std::array<int, 3> array{0, 1, 2};
28+
std::array<int, 3> array{0, 1, 2};
2929

30-
auto too_large = [&] { std::span<int, 3> const s(array.data(), 4); (void)s; };
31-
TEST_LIBCPP_ASSERT_FAILURE(too_large(), "size mismatch in span's constructor (iterator, len)");
30+
// Input range too large (exceeds the span extent)
31+
{
32+
auto f = [&] {
33+
std::span<int, 3> const s(array.data(), 4);
34+
(void)s;
35+
};
36+
TEST_LIBCPP_ASSERT_FAILURE(f(), "size mismatch in span's constructor (iterator, len)");
37+
}
3238

33-
auto too_small = [&] { std::span<int, 3> const s(array.data(), 2); (void)s; };
34-
TEST_LIBCPP_ASSERT_FAILURE(too_small(), "size mismatch in span's constructor (iterator, len)");
39+
// Input range too small (doesn't fill the span)
40+
{
41+
auto f = [&] {
42+
std::span<int, 3> const s(array.data(), 2);
43+
(void)s;
44+
};
45+
TEST_LIBCPP_ASSERT_FAILURE(f(), "size mismatch in span's constructor (iterator, len)");
46+
}
3547

36-
return 0;
48+
// Input range is non-empty but starts with a null pointer
49+
{
50+
// static extent
51+
{
52+
auto f = [&] {
53+
int* p = nullptr;
54+
std::span<int, 3> const s(p, 3);
55+
(void)s;
56+
};
57+
TEST_LIBCPP_ASSERT_FAILURE(f(), "passed nullptr with non-zero length in span's constructor (iterator, len)");
58+
}
59+
60+
// dynamic extent
61+
{
62+
auto f = [&] {
63+
int* p = nullptr;
64+
std::span<int, std::dynamic_extent> const s(p, 1);
65+
(void)s;
66+
};
67+
TEST_LIBCPP_ASSERT_FAILURE(f(), "passed nullptr with non-zero length in span's constructor (iterator, len)");
68+
}
69+
}
70+
71+
return 0;
3772
}

0 commit comments

Comments
 (0)