[libcxx-commits] [libcxx] [libc++][hardening] Add a bounds check for `valarray` and `bitset`. (PR #120685)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Dec 19 22:31:33 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Konstantin Varlamov (var-const)
<details>
<summary>Changes</summary>
Add a `valid-element-access` check to `valarray::operator[]` and
`bitset::operator[]`.
---
Full diff: https://github.com/llvm/llvm-project/pull/120685.diff
5 Files Affected:
- (modified) libcxx/include/bitset (+7-1)
- (modified) libcxx/include/valarray (+8-2)
- (added) libcxx/test/libcxx/numerics/numarray/assert.pass.cpp (+42)
- (added) libcxx/test/libcxx/utilities/template.bitset/assert.abi-v1.pass.cpp (+43)
- (added) libcxx/test/libcxx/utilities/template.bitset/assert.abi-v2.pass.cpp (+45)
``````````diff
diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index e2dc7b459f1c4a..b8c31d5ddd52fe 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -133,6 +133,7 @@ template <size_t N> struct hash<std::bitset<N>>;
# include <__algorithm/fill_n.h>
# include <__algorithm/find.h>
# include <__bit_reference>
+# include <__assert>
# include <__config>
# include <__functional/hash.h>
# include <__functional/unary_function.h>
@@ -682,13 +683,18 @@ public:
// element access:
# ifdef _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const { return __base::__make_ref(__p); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
+ return __base::__make_ref(__p);
+ }
# else
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference operator[](size_t __p) const {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
return __base::__make_ref(__p);
}
# endif
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference operator[](size_t __p) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
return __base::__make_ref(__p);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const;
diff --git a/libcxx/include/valarray b/libcxx/include/valarray
index af916096b5ef9d..e86367dac929df 100644
--- a/libcxx/include/valarray
+++ b/libcxx/include/valarray
@@ -821,9 +821,15 @@ public:
_LIBCPP_HIDE_FROM_ABI valarray& operator=(const __val_expr<_ValExpr>& __v);
// element access:
- _LIBCPP_HIDE_FROM_ABI const value_type& operator[](size_t __i) const { return __begin_[__i]; }
+ _LIBCPP_HIDE_FROM_ABI const value_type& operator[](size_t __i) const {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < size(), "valarray::operator[] index out of bounds");
+ return __begin_[__i];
+ }
- _LIBCPP_HIDE_FROM_ABI value_type& operator[](size_t __i) { return __begin_[__i]; }
+ _LIBCPP_HIDE_FROM_ABI value_type& operator[](size_t __i) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < size(), "valarray::operator[] index out of bounds");
+ return __begin_[__i];
+ }
// subset operations:
_LIBCPP_HIDE_FROM_ABI __val_expr<__slice_expr<const valarray&> > operator[](slice __s) const;
diff --git a/libcxx/test/libcxx/numerics/numarray/assert.pass.cpp b/libcxx/test/libcxx/numerics/numarray/assert.pass.cpp
new file mode 100644
index 00000000000000..2bdf52340abfc8
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/numarray/assert.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <valarray>
+
+// Test hardening assertions for std::valarray.
+
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: libcpp-hardening-mode=none
+// UNSUPPORTED: c++03
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+#include <valarray>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ { // Empty valarray
+ std::valarray<int> c;
+ const auto& const_c = c;
+ TEST_LIBCPP_ASSERT_FAILURE(c[0], "valarray::operator[] index out of bounds");
+ TEST_LIBCPP_ASSERT_FAILURE(const_c[0], "valarray::operator[] index out of bounds");
+ TEST_LIBCPP_ASSERT_FAILURE(c[42], "valarray::operator[] index out of bounds");
+ TEST_LIBCPP_ASSERT_FAILURE(const_c[42], "valarray::operator[] index out of bounds");
+ }
+
+ { // Non-empty valarray
+ std::valarray<int> c(4);
+ const auto& const_c = c;
+ (void)c[3]; // Check that there's no assertion on valid access.
+ TEST_LIBCPP_ASSERT_FAILURE(c[4], "valarray::operator[] index out of bounds");
+ (void)const_c[3]; // Check that there's no assertion on valid access.
+ TEST_LIBCPP_ASSERT_FAILURE(const_c[4], "valarray::operator[] index out of bounds");
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/utilities/template.bitset/assert.abi-v1.pass.cpp b/libcxx/test/libcxx/utilities/template.bitset/assert.abi-v1.pass.cpp
new file mode 100644
index 00000000000000..0abb94954ba554
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/template.bitset/assert.abi-v1.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <bitset>
+
+// Test hardening assertions for std::bitset using ABI v1 (where the const overload of `operator[]` returns
+// `const_reference` which is non-Standard behavior).
+
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: libcpp-hardening-mode=none
+// UNSUPPORTED: c++03
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+#include <bitset>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ { // Empty bitset
+ std::bitset<0> c;
+ const auto& const_c = c;
+ TEST_LIBCPP_ASSERT_FAILURE(c[0], "bitset::operator[] index out of bounds");
+ TEST_LIBCPP_ASSERT_FAILURE(const_c[0], "bitset::operator[] index out of bounds");
+ TEST_LIBCPP_ASSERT_FAILURE(c[42], "bitset::operator[] index out of bounds");
+ TEST_LIBCPP_ASSERT_FAILURE(const_c[42], "bitset::operator[] index out of bounds");
+ }
+
+ { // Non-empty bitset
+ std::bitset<4> c(42);
+ const auto& const_c = c;
+ (void)c[3]; // Check that there's no assertion on valid access.
+ TEST_LIBCPP_ASSERT_FAILURE(c[4], "bitset::operator[] index out of bounds");
+ (void)const_c[3]; // Check that there's no assertion on valid access.
+ TEST_LIBCPP_ASSERT_FAILURE(const_c[4], "bitset::operator[] index out of bounds");
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/utilities/template.bitset/assert.abi-v2.pass.cpp b/libcxx/test/libcxx/utilities/template.bitset/assert.abi-v2.pass.cpp
new file mode 100644
index 00000000000000..783980118207f7
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/template.bitset/assert.abi-v2.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <bitset>
+
+// Test hardening assertions for std::bitset using ABI >= v2 (where the const overload of `operator[]` returns `bool` as
+// mandated by the Standard).
+
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: libcpp-hardening-mode=none
+// UNSUPPORTED: c++03
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL=1
+
+#include <bitset>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ { // Empty bitset
+ std::bitset<0> c;
+ const auto& const_c = c;
+ TEST_LIBCPP_ASSERT_FAILURE(c[0], "bitset::operator[] index out of bounds");
+ TEST_LIBCPP_ASSERT_FAILURE(const_c[0], "bitset::operator[] index out of bounds");
+ TEST_LIBCPP_ASSERT_FAILURE(c[42], "bitset::operator[] index out of bounds");
+ TEST_LIBCPP_ASSERT_FAILURE(const_c[42], "bitset::operator[] index out of bounds");
+ }
+
+ { // Non-empty bitset
+ std::bitset<4> c(42);
+ const auto& const_c = c;
+ (void)c[3]; // Check that there's no assertion on valid access.
+ TEST_LIBCPP_ASSERT_FAILURE(c[4], "bitset::operator[] index out of bounds");
+ (void)const_c[3]; // Check that there's no assertion on valid access.
+ TEST_LIBCPP_ASSERT_FAILURE(const_c[4], "bitset::operator[] index out of bounds");
+ }
+
+ return 0;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/120685
More information about the libcxx-commits
mailing list