diff --git a/libcxx/docs/Hardening.rst b/libcxx/docs/Hardening.rst index 42aacfdcfb41a..4002f40e1dad3 100644 --- a/libcxx/docs/Hardening.rst +++ b/libcxx/docs/Hardening.rst @@ -458,7 +458,7 @@ Hardened containers status - Partial - N/A * - ``bitset`` - - ❌ + - ✅ - N/A Note: for ``vector`` and ``string``, the iterator does not check for diff --git a/libcxx/include/bitset b/libcxx/include/bitset index e2dc7b459f1c4..df9fdfe6dd9ef 100644 --- a/libcxx/include/bitset +++ b/libcxx/include/bitset @@ -132,6 +132,7 @@ template struct hash>; # include <__algorithm/fill.h> # include <__algorithm/fill_n.h> # include <__algorithm/find.h> +# include <__assert> # include <__bit_reference> # include <__config> # include <__functional/hash.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 af916096b5ef9..e86367dac929d 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 > 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 0000000000000..2bdf52340abfc --- /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 +// +//===----------------------------------------------------------------------===// + +// + +// 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 + +#include "check_assertion.h" + +int main(int, char**) { + { // Empty valarray + std::valarray 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 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.pass.cpp b/libcxx/test/libcxx/utilities/template.bitset/assert.pass.cpp new file mode 100644 index 0000000000000..4019bdf1318eb --- /dev/null +++ b/libcxx/test/libcxx/utilities/template.bitset/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 +// +//===----------------------------------------------------------------------===// + +// + +// Test hardening assertions for std::bitset. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: c++03 +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +#include + +#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/std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp b/libcxx/test/std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp index e8ab264f4bab6..d87fd91b0356c 100644 --- a/libcxx/test/std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp +++ b/libcxx/test/std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000 + // bitset& operator&=(const bitset& rhs); // constexpr since C++23 #include