-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++][hardening] Add checks to forward_list
element access.
#120858
Conversation
In our implementation, failing these checks would result in a null pointer access rather than an out-of-bounds access.
@llvm/pr-subscribers-libcxx Author: Konstantin Varlamov (var-const) ChangesIn our implementation, failing these checks would result in a null Full diff: https://github.com/llvm/llvm-project/pull/120858.diff 2 Files Affected:
diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index c1ab155d5a133e..aa603da84f856e 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -766,8 +766,14 @@ public:
return std::min<size_type>(__node_traits::max_size(this->__alloc_), numeric_limits<difference_type>::max());
}
- _LIBCPP_HIDE_FROM_ABI reference front() { return __base::__before_begin()->__next_->__get_value(); }
- _LIBCPP_HIDE_FROM_ABI const_reference front() const { return __base::__before_begin()->__next_->__get_value(); }
+ _LIBCPP_HIDE_FROM_ABI reference front() {
+ _LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::front called on an empty list");
+ return __base::__before_begin()->__next_->__get_value();
+ }
+ _LIBCPP_HIDE_FROM_ABI const_reference front() const {
+ _LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::front called on an empty list");
+ return __base::__before_begin()->__next_->__get_value();
+ }
# ifndef _LIBCPP_CXX03_LANG
# if _LIBCPP_STD_VER >= 17
@@ -1085,6 +1091,7 @@ void forward_list<_Tp, _Alloc>::push_front(const value_type& __v) {
template <class _Tp, class _Alloc>
void forward_list<_Tp, _Alloc>::pop_front() {
+ _LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::pop_front called on an empty list");
__node_pointer __p = __base::__before_begin()->__next_;
__base::__before_begin()->__next_ = __p->__next_;
this->__delete_node(__p);
diff --git a/libcxx/test/libcxx/containers/sequences/forwardlist/assert.pass.cpp b/libcxx/test/libcxx/containers/sequences/forwardlist/assert.pass.cpp
new file mode 100644
index 00000000000000..e442d75a5904d6
--- /dev/null
+++ b/libcxx/test/libcxx/containers/sequences/forwardlist/assert.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
+//
+//===----------------------------------------------------------------------===//
+
+// <forward_list>
+
+// Test hardening assertions for std::forward_list.
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// UNSUPPORTED: c++03
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+#include <forward_list>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ { // Default-constructed list.
+ std::forward_list<int> c;
+ const auto& const_c = c;
+ TEST_LIBCPP_ASSERT_FAILURE(c.front(), "forward_list::front called on an empty list");
+ TEST_LIBCPP_ASSERT_FAILURE(const_c.front(), "forward_list::front called on an empty list");
+ TEST_LIBCPP_ASSERT_FAILURE(c.pop_front(), "forward_list::pop_front called on an empty list");
+ }
+
+ { // Non-empty list becomes empty.
+ std::forward_list<int> c;
+ const auto& const_c = c;
+ c.push_front(1);
+
+ (void)c.front(); // Check that there's no assertion on valid access.
+ (void)const_c.front(); // Check that there's no assertion on valid access.
+ c.pop_front();
+ TEST_LIBCPP_ASSERT_FAILURE(c.pop_front(), "forward_list::pop_front called on an empty list");
+ TEST_LIBCPP_ASSERT_FAILURE(c.front(), "forward_list::front called on an empty list");
+ TEST_LIBCPP_ASSERT_FAILURE(const_c.front(), "forward_list::front called on an empty list");
+ }
+
+ return 0;
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
In our implementation, failing these checks would result in a null
pointer access rather than an out-of-bounds access.