While working on fancy pointer support for the linked lists I noticed
they didn't have any debug assertions. This adds the obvious non-empty
assertions to front(), back(), pop_front() and pop_back().
For the pop members, adding an assertion to the underlying function
that
erases a member means it also check erase(end()), which is always
invalid, and erase(begin()) on an empty list. For those erase
members we
can also add a check so that we return without doing anything if the
assertion is disabled, but would have failed had it been enabled.
libstdc++-v3/ChangeLog:
* include/bits/forward_list.h (forward_list::front): Add
non-empty assertions.
* include/bits/forward_list.tcc
(_Fwd_list_base::_M_erase_after):
Likewise. Return immediately if argument is invalid.
* include/bits/stl_list.h (list::front, list::back): Add
non-empty assertions.
(list::_M_erase): Likewise. Return immediately if argument is
invalid.
---
Tested x86_64-linux.
As pull request: https://forge.sourceware.org/gcc/gcc-TEST/pulls/26
libstdc++-v3/include/bits/forward_list.h | 3 +++
libstdc++-v3/include/bits/forward_list.tcc | 6 ++++++
libstdc++-v3/include/bits/stl_list.h | 19 +++++++++++++++++--
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/libstdc++-v3/include/bits/forward_list.h
b/libstdc++-v3/include/bits/forward_list.h
index c9238cef96f..3fac657518c 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -42,6 +42,7 @@
#include <bits/allocator.h>
#include <ext/alloc_traits.h>
#include <ext/aligned_buffer.h>
+#include <debug/assertions.h>
#if __glibcxx_ranges_to_container // C++ >= 23
# include <bits/ranges_base.h> // ranges::begin, ranges::distance
etc.
# include <bits/ranges_util.h> // ranges::subrange
@@ -884,6 +885,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
reference
front()
{
+ __glibcxx_requires_nonempty();
_Node* __front =
static_cast<_Node*>(this->_M_impl._M_head._M_next);
return *__front->_M_valptr();
}
@@ -896,6 +898,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
const_reference
front() const
{
+ __glibcxx_requires_nonempty();
_Node* __front =
static_cast<_Node*>(this->_M_impl._M_head._M_next);
return *__front->_M_valptr();
}
diff --git a/libstdc++-v3/include/bits/forward_list.tcc
b/libstdc++-v3/include/bits/forward_list.tcc
index 9750c7c0502..50acdb9f26b 100644
--- a/libstdc++-v3/include/bits/forward_list.tcc
+++ b/libstdc++-v3/include/bits/forward_list.tcc
@@ -63,6 +63,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_Fwd_list_base<_Tp, _Alloc>::
_M_erase_after(_Fwd_list_node_base* __pos)
{
+ if (__pos == nullptr || __pos->_M_next == nullptr)
[[__unlikely__]]
+ {
+ __glibcxx_assert(__pos != nullptr && __pos->_M_next !=
nullptr);
+ return nullptr;
+ }
+
_Node* __curr = static_cast<_Node*>(__pos->_M_next);
__pos->_M_next = __curr->_M_next;
_Node_alloc_traits::destroy(_M_get_Node_allocator(),
diff --git a/libstdc++-v3/include/bits/stl_list.h
b/libstdc++-v3/include/bits/stl_list.h
index 7deb04b4bfe..d70ba90b8fa 100644
--- a/libstdc++-v3/include/bits/stl_list.h
+++ b/libstdc++-v3/include/bits/stl_list.h
@@ -59,6 +59,7 @@
#include <bits/concept_check.h>
#include <ext/alloc_traits.h>
+#include <debug/assertions.h>
#if __cplusplus >= 201103L
#include <initializer_list>
#include <bits/allocated_ptr.h>
@@ -1249,7 +1250,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_GLIBCXX_NODISCARD
reference
front() _GLIBCXX_NOEXCEPT
- { return *begin(); }
+ {
+ __glibcxx_requires_nonempty();
+ return *begin();
+ }
/**
* Returns a read-only (constant) reference to the data at
the first
@@ -1258,7 +1262,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_GLIBCXX_NODISCARD
const_reference
front() const _GLIBCXX_NOEXCEPT
- { return *begin(); }
+ {
+ __glibcxx_requires_nonempty();
+ return *begin();
+ }
/**
* Returns a read/write reference to the data at the last
element
@@ -1268,6 +1275,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
reference
back() _GLIBCXX_NOEXCEPT
{
+ __glibcxx_requires_nonempty();
iterator __tmp = end();
--__tmp;
return *__tmp;
@@ -1281,6 +1289,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
const_reference
back() const _GLIBCXX_NOEXCEPT
{
+ __glibcxx_requires_nonempty();
const_iterator __tmp = end();
--__tmp;
return *__tmp;
@@ -2132,6 +2141,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
void
_M_erase(iterator __position) _GLIBCXX_NOEXCEPT
{
+ if (__builtin_expect(empty(), 0))
+ {
+ __glibcxx_requires_nonempty();
+ return;
+ }