[libcxx-commits] [libcxx] [libc++][hardening] Add checks to `forward_list` element access. (PR #120858)
Konstantin Varlamov via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Dec 21 17:43:12 PST 2024
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/120858
>From efc849d93f8da1f09b50cd34de0ab91379ebcb0d Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconst at apple.com>
Date: Sat, 21 Dec 2024 14:52:11 -0800
Subject: [PATCH 1/3] [libc++][hardening] Add checks to `forward_list` element
access.
In our implementation, failing these checks would result in a null
pointer access rather than an out-of-bounds access.
---
libcxx/include/forward_list | 11 ++++-
.../sequences/forwardlist/assert.pass.cpp | 45 +++++++++++++++++++
2 files changed, 54 insertions(+), 2 deletions(-)
create mode 100644 libcxx/test/libcxx/containers/sequences/forwardlist/assert.pass.cpp
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;
+}
>From a443582eb4837c4a8b233d7ea827512c91ab1183 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconst at apple.com>
Date: Sat, 21 Dec 2024 15:10:23 -0800
Subject: [PATCH 2/3] Formatting
---
.../libcxx/containers/sequences/forwardlist/assert.pass.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/libcxx/containers/sequences/forwardlist/assert.pass.cpp b/libcxx/test/libcxx/containers/sequences/forwardlist/assert.pass.cpp
index e442d75a5904d6..6d1748e6450256 100644
--- a/libcxx/test/libcxx/containers/sequences/forwardlist/assert.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/forwardlist/assert.pass.cpp
@@ -33,8 +33,10 @@ int main(int, char**) {
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.
+ // Check that there's no assertion on valid access.
+ (void)c.front();
+ (void)const_c.front();
+
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");
>From 3360715ea55286dae0699d1556bd1664680b4c4a Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconst at apple.com>
Date: Sat, 21 Dec 2024 17:42:55 -0800
Subject: [PATCH 3/3] Fix CI
---
libcxx/include/forward_list | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index aa603da84f856e..ea854ea828b3be 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -202,6 +202,7 @@ template <class T, class Allocator, class Predicate>
# include <__algorithm/lexicographical_compare.h>
# include <__algorithm/lexicographical_compare_three_way.h>
# include <__algorithm/min.h>
+# include <__assert>
# include <__config>
# include <__cstddef/nullptr_t.h>
# include <__iterator/distance.h>
More information about the libcxx-commits
mailing list