Skip to content

Commit

Permalink
[libc++][hardening] Add checks to forward_list element access. (llv…
Browse files Browse the repository at this point in the history
…m#120858)

In our implementation, failing these checks would result in a null
pointer access rather than an out-of-bounds access.
  • Loading branch information
var-const authored Jan 6, 2025
1 parent 774c226 commit bda7c9a
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 3 deletions.
2 changes: 1 addition & 1 deletion libcxx/docs/Hardening.rst
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ Hardened containers status
- ✅
- ❌
* - ``forward_list``
-
-
- ❌
* - ``deque``
- ✅
Expand Down
12 changes: 10 additions & 2 deletions libcxx/include/forward_list
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -766,8 +767,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
Expand Down Expand Up @@ -1085,6 +1092,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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===----------------------------------------------------------------------===//
//
// 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);

// 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");
TEST_LIBCPP_ASSERT_FAILURE(const_c.front(), "forward_list::front called on an empty list");
}

return 0;
}

0 comments on commit bda7c9a

Please sign in to comment.