Skip to content

Commit 2511489

Browse files
committed
[libc++][hardening] Add a bounds check for valarray and bitset.
Add a `valid-element-access` check to `valarray::operator[]` and `bitset::operator[]`.
1 parent 918d455 commit 2511489

File tree

5 files changed

+145
-3
lines changed

5 files changed

+145
-3
lines changed

libcxx/include/bitset

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ template <size_t N> struct hash<std::bitset<N>>;
133133
# include <__algorithm/fill_n.h>
134134
# include <__algorithm/find.h>
135135
# include <__bit_reference>
136+
# include <__assert>
136137
# include <__config>
137138
# include <__functional/hash.h>
138139
# include <__functional/unary_function.h>
@@ -682,13 +683,18 @@ public:
682683

683684
// element access:
684685
# ifdef _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL
685-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const { return __base::__make_ref(__p); }
686+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const {
687+
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
688+
return __base::__make_ref(__p);
689+
}
686690
# else
687691
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference operator[](size_t __p) const {
692+
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
688693
return __base::__make_ref(__p);
689694
}
690695
# endif
691696
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference operator[](size_t __p) {
697+
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
692698
return __base::__make_ref(__p);
693699
}
694700
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const;

libcxx/include/valarray

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -821,9 +821,15 @@ public:
821821
_LIBCPP_HIDE_FROM_ABI valarray& operator=(const __val_expr<_ValExpr>& __v);
822822

823823
// element access:
824-
_LIBCPP_HIDE_FROM_ABI const value_type& operator[](size_t __i) const { return __begin_[__i]; }
824+
_LIBCPP_HIDE_FROM_ABI const value_type& operator[](size_t __i) const {
825+
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < size(), "valarray::operator[] index out of bounds");
826+
return __begin_[__i];
827+
}
825828

826-
_LIBCPP_HIDE_FROM_ABI value_type& operator[](size_t __i) { return __begin_[__i]; }
829+
_LIBCPP_HIDE_FROM_ABI value_type& operator[](size_t __i) {
830+
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < size(), "valarray::operator[] index out of bounds");
831+
return __begin_[__i];
832+
}
827833

828834
// subset operations:
829835
_LIBCPP_HIDE_FROM_ABI __val_expr<__slice_expr<const valarray&> > operator[](slice __s) const;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <valarray>
10+
11+
// Test hardening assertions for std::valarray.
12+
13+
// REQUIRES: has-unix-headers
14+
// UNSUPPORTED: libcpp-hardening-mode=none
15+
// UNSUPPORTED: c++03
16+
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
17+
18+
#include <valarray>
19+
20+
#include "check_assertion.h"
21+
22+
int main(int, char**) {
23+
{ // Empty valarray
24+
std::valarray<int> c;
25+
const auto& const_c = c;
26+
TEST_LIBCPP_ASSERT_FAILURE(c[0], "valarray::operator[] index out of bounds");
27+
TEST_LIBCPP_ASSERT_FAILURE(const_c[0], "valarray::operator[] index out of bounds");
28+
TEST_LIBCPP_ASSERT_FAILURE(c[42], "valarray::operator[] index out of bounds");
29+
TEST_LIBCPP_ASSERT_FAILURE(const_c[42], "valarray::operator[] index out of bounds");
30+
}
31+
32+
{ // Non-empty valarray
33+
std::valarray<int> c(4);
34+
const auto& const_c = c;
35+
(void)c[3]; // Check that there's no assertion on valid access.
36+
TEST_LIBCPP_ASSERT_FAILURE(c[4], "valarray::operator[] index out of bounds");
37+
(void)const_c[3]; // Check that there's no assertion on valid access.
38+
TEST_LIBCPP_ASSERT_FAILURE(const_c[4], "valarray::operator[] index out of bounds");
39+
}
40+
41+
return 0;
42+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <bitset>
10+
11+
// Test hardening assertions for std::bitset using ABI v1 (where the const overload of `operator[]` returns
12+
// `const_reference` which is non-Standard behavior).
13+
14+
// REQUIRES: has-unix-headers
15+
// UNSUPPORTED: libcpp-hardening-mode=none
16+
// UNSUPPORTED: c++03
17+
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
18+
19+
#include <bitset>
20+
21+
#include "check_assertion.h"
22+
23+
int main(int, char**) {
24+
{ // Empty bitset
25+
std::bitset<0> c;
26+
const auto& const_c = c;
27+
TEST_LIBCPP_ASSERT_FAILURE(c[0], "bitset::operator[] index out of bounds");
28+
TEST_LIBCPP_ASSERT_FAILURE(const_c[0], "bitset::operator[] index out of bounds");
29+
TEST_LIBCPP_ASSERT_FAILURE(c[42], "bitset::operator[] index out of bounds");
30+
TEST_LIBCPP_ASSERT_FAILURE(const_c[42], "bitset::operator[] index out of bounds");
31+
}
32+
33+
{ // Non-empty bitset
34+
std::bitset<4> c(42);
35+
const auto& const_c = c;
36+
(void)c[3]; // Check that there's no assertion on valid access.
37+
TEST_LIBCPP_ASSERT_FAILURE(c[4], "bitset::operator[] index out of bounds");
38+
(void)const_c[3]; // Check that there's no assertion on valid access.
39+
TEST_LIBCPP_ASSERT_FAILURE(const_c[4], "bitset::operator[] index out of bounds");
40+
}
41+
42+
return 0;
43+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <bitset>
10+
11+
// Test hardening assertions for std::bitset using ABI >= v2 (where the const overload of `operator[]` returns `bool` as
12+
// mandated by the Standard).
13+
14+
// REQUIRES: has-unix-headers
15+
// UNSUPPORTED: libcpp-hardening-mode=none
16+
// UNSUPPORTED: c++03
17+
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
18+
19+
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL=1
20+
21+
#include <bitset>
22+
23+
#include "check_assertion.h"
24+
25+
int main(int, char**) {
26+
{ // Empty bitset
27+
std::bitset<0> c;
28+
const auto& const_c = c;
29+
TEST_LIBCPP_ASSERT_FAILURE(c[0], "bitset::operator[] index out of bounds");
30+
TEST_LIBCPP_ASSERT_FAILURE(const_c[0], "bitset::operator[] index out of bounds");
31+
TEST_LIBCPP_ASSERT_FAILURE(c[42], "bitset::operator[] index out of bounds");
32+
TEST_LIBCPP_ASSERT_FAILURE(const_c[42], "bitset::operator[] index out of bounds");
33+
}
34+
35+
{ // Non-empty bitset
36+
std::bitset<4> c(42);
37+
const auto& const_c = c;
38+
(void)c[3]; // Check that there's no assertion on valid access.
39+
TEST_LIBCPP_ASSERT_FAILURE(c[4], "bitset::operator[] index out of bounds");
40+
(void)const_c[3]; // Check that there's no assertion on valid access.
41+
TEST_LIBCPP_ASSERT_FAILURE(const_c[4], "bitset::operator[] index out of bounds");
42+
}
43+
44+
return 0;
45+
}

0 commit comments

Comments
 (0)