Skip to content

Commit efc849d

Browse files
committed
[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.
1 parent fd78472 commit efc849d

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

libcxx/include/forward_list

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,8 +766,14 @@ public:
766766
return std::min<size_type>(__node_traits::max_size(this->__alloc_), numeric_limits<difference_type>::max());
767767
}
768768

769-
_LIBCPP_HIDE_FROM_ABI reference front() { return __base::__before_begin()->__next_->__get_value(); }
770-
_LIBCPP_HIDE_FROM_ABI const_reference front() const { return __base::__before_begin()->__next_->__get_value(); }
769+
_LIBCPP_HIDE_FROM_ABI reference front() {
770+
_LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::front called on an empty list");
771+
return __base::__before_begin()->__next_->__get_value();
772+
}
773+
_LIBCPP_HIDE_FROM_ABI const_reference front() const {
774+
_LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::front called on an empty list");
775+
return __base::__before_begin()->__next_->__get_value();
776+
}
771777

772778
# ifndef _LIBCPP_CXX03_LANG
773779
# if _LIBCPP_STD_VER >= 17
@@ -1085,6 +1091,7 @@ void forward_list<_Tp, _Alloc>::push_front(const value_type& __v) {
10851091

10861092
template <class _Tp, class _Alloc>
10871093
void forward_list<_Tp, _Alloc>::pop_front() {
1094+
_LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::pop_front called on an empty list");
10881095
__node_pointer __p = __base::__before_begin()->__next_;
10891096
__base::__before_begin()->__next_ = __p->__next_;
10901097
this->__delete_node(__p);
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+
// <forward_list>
10+
11+
// Test hardening assertions for std::forward_list.
12+
13+
// REQUIRES: has-unix-headers
14+
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
15+
// UNSUPPORTED: c++03
16+
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
17+
18+
#include <forward_list>
19+
20+
#include "check_assertion.h"
21+
22+
int main(int, char**) {
23+
{ // Default-constructed list.
24+
std::forward_list<int> c;
25+
const auto& const_c = c;
26+
TEST_LIBCPP_ASSERT_FAILURE(c.front(), "forward_list::front called on an empty list");
27+
TEST_LIBCPP_ASSERT_FAILURE(const_c.front(), "forward_list::front called on an empty list");
28+
TEST_LIBCPP_ASSERT_FAILURE(c.pop_front(), "forward_list::pop_front called on an empty list");
29+
}
30+
31+
{ // Non-empty list becomes empty.
32+
std::forward_list<int> c;
33+
const auto& const_c = c;
34+
c.push_front(1);
35+
36+
(void)c.front(); // Check that there's no assertion on valid access.
37+
(void)const_c.front(); // Check that there's no assertion on valid access.
38+
c.pop_front();
39+
TEST_LIBCPP_ASSERT_FAILURE(c.pop_front(), "forward_list::pop_front called on an empty list");
40+
TEST_LIBCPP_ASSERT_FAILURE(c.front(), "forward_list::front called on an empty list");
41+
TEST_LIBCPP_ASSERT_FAILURE(const_c.front(), "forward_list::front called on an empty list");
42+
}
43+
44+
return 0;
45+
}

0 commit comments

Comments
 (0)