2010-05-11 19:42:16 +00:00
|
|
|
// -*- C++ -*-
|
2021-11-17 21:25:01 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2010-05-11 19:42:16 +00:00
|
|
|
//
|
2019-01-19 10:56:40 +00:00
|
|
|
// 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
|
2010-05-11 19:42:16 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef _LIBCPP_DEQUE
|
|
|
|
#define _LIBCPP_DEQUE
|
|
|
|
|
|
|
|
/*
|
|
|
|
deque synopsis
|
|
|
|
|
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
|
|
|
|
template <class T, class Allocator = allocator<T> >
|
|
|
|
class deque
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// types:
|
|
|
|
typedef T value_type;
|
|
|
|
typedef Allocator allocator_type;
|
|
|
|
|
|
|
|
typedef typename allocator_type::reference reference;
|
|
|
|
typedef typename allocator_type::const_reference const_reference;
|
|
|
|
typedef implementation-defined iterator;
|
|
|
|
typedef implementation-defined const_iterator;
|
|
|
|
typedef typename allocator_type::size_type size_type;
|
|
|
|
typedef typename allocator_type::difference_type difference_type;
|
|
|
|
|
|
|
|
typedef typename allocator_type::pointer pointer;
|
|
|
|
typedef typename allocator_type::const_pointer const_pointer;
|
|
|
|
typedef std::reverse_iterator<iterator> reverse_iterator;
|
|
|
|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
|
|
|
|
|
|
|
// construct/copy/destroy:
|
2011-06-03 15:16:49 +00:00
|
|
|
deque() noexcept(is_nothrow_default_constructible<allocator_type>::value);
|
2010-05-11 19:42:16 +00:00
|
|
|
explicit deque(const allocator_type& a);
|
|
|
|
explicit deque(size_type n);
|
2013-09-09 18:19:45 +00:00
|
|
|
explicit deque(size_type n, const allocator_type& a); // C++14
|
2010-05-11 19:42:16 +00:00
|
|
|
deque(size_type n, const value_type& v);
|
|
|
|
deque(size_type n, const value_type& v, const allocator_type& a);
|
|
|
|
template <class InputIterator>
|
|
|
|
deque(InputIterator f, InputIterator l);
|
|
|
|
template <class InputIterator>
|
|
|
|
deque(InputIterator f, InputIterator l, const allocator_type& a);
|
2023-05-17 07:48:24 +00:00
|
|
|
template<container-compatible-range<T> R>
|
|
|
|
deque(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23
|
2010-05-11 19:42:16 +00:00
|
|
|
deque(const deque& c);
|
2011-06-02 21:38:57 +00:00
|
|
|
deque(deque&& c)
|
|
|
|
noexcept(is_nothrow_move_constructible<allocator_type>::value);
|
2010-05-11 19:42:16 +00:00
|
|
|
deque(initializer_list<value_type> il, const Allocator& a = allocator_type());
|
|
|
|
deque(const deque& c, const allocator_type& a);
|
|
|
|
deque(deque&& c, const allocator_type& a);
|
|
|
|
~deque();
|
|
|
|
|
|
|
|
deque& operator=(const deque& c);
|
2011-06-02 21:38:57 +00:00
|
|
|
deque& operator=(deque&& c)
|
|
|
|
noexcept(
|
|
|
|
allocator_type::propagate_on_container_move_assignment::value &&
|
|
|
|
is_nothrow_move_assignable<allocator_type>::value);
|
2010-05-11 19:42:16 +00:00
|
|
|
deque& operator=(initializer_list<value_type> il);
|
|
|
|
|
|
|
|
template <class InputIterator>
|
|
|
|
void assign(InputIterator f, InputIterator l);
|
2023-05-17 07:48:24 +00:00
|
|
|
template<container-compatible-range<T> R>
|
|
|
|
void assign_range(R&& rg); // C++23
|
2010-05-11 19:42:16 +00:00
|
|
|
void assign(size_type n, const value_type& v);
|
|
|
|
void assign(initializer_list<value_type> il);
|
|
|
|
|
2011-06-02 16:10:22 +00:00
|
|
|
allocator_type get_allocator() const noexcept;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
// iterators:
|
|
|
|
|
2011-06-02 16:10:22 +00:00
|
|
|
iterator begin() noexcept;
|
|
|
|
const_iterator begin() const noexcept;
|
|
|
|
iterator end() noexcept;
|
|
|
|
const_iterator end() const noexcept;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2011-06-02 16:10:22 +00:00
|
|
|
reverse_iterator rbegin() noexcept;
|
|
|
|
const_reverse_iterator rbegin() const noexcept;
|
|
|
|
reverse_iterator rend() noexcept;
|
|
|
|
const_reverse_iterator rend() const noexcept;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2011-06-02 16:10:22 +00:00
|
|
|
const_iterator cbegin() const noexcept;
|
|
|
|
const_iterator cend() const noexcept;
|
|
|
|
const_reverse_iterator crbegin() const noexcept;
|
|
|
|
const_reverse_iterator crend() const noexcept;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
// capacity:
|
2011-06-02 16:10:22 +00:00
|
|
|
size_type size() const noexcept;
|
|
|
|
size_type max_size() const noexcept;
|
2010-05-11 19:42:16 +00:00
|
|
|
void resize(size_type n);
|
|
|
|
void resize(size_type n, const value_type& v);
|
|
|
|
void shrink_to_fit();
|
2011-06-02 16:10:22 +00:00
|
|
|
bool empty() const noexcept;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
// element access:
|
|
|
|
reference operator[](size_type i);
|
|
|
|
const_reference operator[](size_type i) const;
|
|
|
|
reference at(size_type i);
|
|
|
|
const_reference at(size_type i) const;
|
|
|
|
reference front();
|
|
|
|
const_reference front() const;
|
|
|
|
reference back();
|
|
|
|
const_reference back() const;
|
|
|
|
|
|
|
|
// modifiers:
|
|
|
|
void push_front(const value_type& v);
|
|
|
|
void push_front(value_type&& v);
|
2023-05-17 07:48:24 +00:00
|
|
|
template<container-compatible-range<T> R>
|
|
|
|
void prepend_range(R&& rg); // C++23
|
2010-05-11 19:42:16 +00:00
|
|
|
void push_back(const value_type& v);
|
|
|
|
void push_back(value_type&& v);
|
2023-05-17 07:48:24 +00:00
|
|
|
template<container-compatible-range<T> R>
|
|
|
|
void append_range(R&& rg); // C++23
|
2017-01-24 23:09:12 +00:00
|
|
|
template <class... Args> reference emplace_front(Args&&... args); // reference in C++17
|
|
|
|
template <class... Args> reference emplace_back(Args&&... args); // reference in C++17
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class... Args> iterator emplace(const_iterator p, Args&&... args);
|
|
|
|
iterator insert(const_iterator p, const value_type& v);
|
|
|
|
iterator insert(const_iterator p, value_type&& v);
|
|
|
|
iterator insert(const_iterator p, size_type n, const value_type& v);
|
|
|
|
template <class InputIterator>
|
2015-01-22 18:33:29 +00:00
|
|
|
iterator insert(const_iterator p, InputIterator f, InputIterator l);
|
2023-05-17 07:48:24 +00:00
|
|
|
template<container-compatible-range<T> R>
|
|
|
|
iterator insert_range(const_iterator position, R&& rg); // C++23
|
2010-05-11 19:42:16 +00:00
|
|
|
iterator insert(const_iterator p, initializer_list<value_type> il);
|
|
|
|
void pop_front();
|
|
|
|
void pop_back();
|
|
|
|
iterator erase(const_iterator p);
|
|
|
|
iterator erase(const_iterator f, const_iterator l);
|
2011-06-02 21:38:57 +00:00
|
|
|
void swap(deque& c)
|
2015-07-13 20:04:56 +00:00
|
|
|
noexcept(allocator_traits<allocator_type>::is_always_equal::value); // C++17
|
2011-06-02 16:10:22 +00:00
|
|
|
void clear() noexcept;
|
2010-05-11 19:42:16 +00:00
|
|
|
};
|
|
|
|
|
2018-05-18 23:44:13 +00:00
|
|
|
template <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
|
|
|
|
deque(InputIterator, InputIterator, Allocator = Allocator())
|
2021-11-09 17:21:02 +00:00
|
|
|
-> deque<typename iterator_traits<InputIterator>::value_type, Allocator>; // C++17
|
2018-05-18 23:44:13 +00:00
|
|
|
|
2023-05-17 07:48:24 +00:00
|
|
|
template<ranges::input_range R, class Allocator = allocator<ranges::range_value_t<R>>>
|
|
|
|
deque(from_range_t, R&&, Allocator = Allocator())
|
|
|
|
-> deque<ranges::range_value_t<R>, Allocator>; // C++23
|
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class T, class Allocator>
|
|
|
|
bool operator==(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
|
|
|
|
template <class T, class Allocator>
|
2023-03-03 12:35:07 +00:00
|
|
|
bool operator< (const deque<T,Allocator>& x, const deque<T,Allocator>& y); // removed in C++20
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class T, class Allocator>
|
2023-03-03 12:35:07 +00:00
|
|
|
bool operator!=(const deque<T,Allocator>& x, const deque<T,Allocator>& y); // removed in C++20
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class T, class Allocator>
|
2023-03-03 12:35:07 +00:00
|
|
|
bool operator> (const deque<T,Allocator>& x, const deque<T,Allocator>& y); // removed in C++20
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class T, class Allocator>
|
2023-03-03 12:35:07 +00:00
|
|
|
bool operator>=(const deque<T,Allocator>& x, const deque<T,Allocator>& y); // removed in C++20
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class T, class Allocator>
|
2023-03-03 12:35:07 +00:00
|
|
|
bool operator<=(const deque<T,Allocator>& x, const deque<T,Allocator>& y); // removed in C++20
|
|
|
|
template<class T, class Allocator>
|
|
|
|
synth-three-way-result<T> operator<=>(const deque<T, Allocator>& x,
|
|
|
|
const deque<T, Allocator>& y); // since C++20
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
// specialized algorithms:
|
|
|
|
template <class T, class Allocator>
|
2011-06-03 17:30:28 +00:00
|
|
|
void swap(deque<T,Allocator>& x, deque<T,Allocator>& y)
|
|
|
|
noexcept(noexcept(x.swap(y)));
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2018-12-14 18:49:35 +00:00
|
|
|
template <class T, class Allocator, class U>
|
2020-05-02 11:58:03 +00:00
|
|
|
typename deque<T, Allocator>::size_type
|
|
|
|
erase(deque<T, Allocator>& c, const U& value); // C++20
|
2018-12-14 18:49:35 +00:00
|
|
|
template <class T, class Allocator, class Predicate>
|
2020-05-02 11:58:03 +00:00
|
|
|
typename deque<T, Allocator>::size_type
|
|
|
|
erase_if(deque<T, Allocator>& c, Predicate pred); // C++20
|
2018-12-14 18:49:35 +00:00
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
} // std
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2022-02-15 17:18:08 +00:00
|
|
|
#include <__algorithm/copy.h>
|
|
|
|
#include <__algorithm/copy_backward.h>
|
2023-05-17 07:48:24 +00:00
|
|
|
#include <__algorithm/copy_n.h>
|
2022-02-15 17:18:08 +00:00
|
|
|
#include <__algorithm/equal.h>
|
|
|
|
#include <__algorithm/fill_n.h>
|
|
|
|
#include <__algorithm/lexicographical_compare.h>
|
2023-03-03 12:35:07 +00:00
|
|
|
#include <__algorithm/lexicographical_compare_three_way.h>
|
2022-02-15 17:18:08 +00:00
|
|
|
#include <__algorithm/min.h>
|
|
|
|
#include <__algorithm/remove.h>
|
|
|
|
#include <__algorithm/remove_if.h>
|
|
|
|
#include <__algorithm/unwrap_iter.h>
|
2022-03-25 16:55:36 +00:00
|
|
|
#include <__assert> // all public C++ headers provide the assertion handler
|
2023-03-29 20:48:20 +00:00
|
|
|
#include <__availability>
|
2010-05-11 19:42:16 +00:00
|
|
|
#include <__config>
|
2021-09-26 13:47:42 +00:00
|
|
|
#include <__format/enable_insertable.h>
|
2023-05-17 07:48:24 +00:00
|
|
|
#include <__iterator/distance.h>
|
2021-11-09 17:21:02 +00:00
|
|
|
#include <__iterator/iterator_traits.h>
|
2022-06-10 17:53:10 +00:00
|
|
|
#include <__iterator/next.h>
|
|
|
|
#include <__iterator/prev.h>
|
|
|
|
#include <__iterator/reverse_iterator.h>
|
2022-11-20 22:16:20 +00:00
|
|
|
#include <__iterator/segmented_iterator.h>
|
2023-03-01 19:13:55 +00:00
|
|
|
#include <__memory/addressof.h>
|
2022-09-22 19:53:13 +00:00
|
|
|
#include <__memory/allocator_destructor.h>
|
2022-09-04 22:01:15 +00:00
|
|
|
#include <__memory/pointer_traits.h>
|
|
|
|
#include <__memory/temp_value.h>
|
|
|
|
#include <__memory/unique_ptr.h>
|
2022-10-06 20:53:30 +00:00
|
|
|
#include <__memory_resource/polymorphic_allocator.h>
|
2023-05-17 07:48:24 +00:00
|
|
|
#include <__ranges/access.h>
|
|
|
|
#include <__ranges/concepts.h>
|
|
|
|
#include <__ranges/container_compatible_range.h>
|
|
|
|
#include <__ranges/from_range.h>
|
|
|
|
#include <__ranges/size.h>
|
2010-05-11 19:42:16 +00:00
|
|
|
#include <__split_buffer>
|
2022-09-04 22:01:15 +00:00
|
|
|
#include <__type_traits/is_allocator.h>
|
2023-03-01 19:13:55 +00:00
|
|
|
#include <__type_traits/is_convertible.h>
|
2023-02-12 11:32:36 +00:00
|
|
|
#include <__type_traits/is_same.h>
|
|
|
|
#include <__type_traits/type_identity.h>
|
2021-06-05 02:47:47 +00:00
|
|
|
#include <__utility/forward.h>
|
2022-03-05 18:17:07 +00:00
|
|
|
#include <__utility/move.h>
|
2023-05-17 07:48:24 +00:00
|
|
|
#include <__utility/pair.h>
|
2022-03-05 18:17:07 +00:00
|
|
|
#include <__utility/swap.h>
|
2021-06-09 23:10:17 +00:00
|
|
|
#include <limits>
|
2010-05-11 19:42:16 +00:00
|
|
|
#include <stdexcept>
|
2018-09-12 19:41:40 +00:00
|
|
|
#include <version>
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-06-16 20:43:46 +00:00
|
|
|
// standard-mandated includes
|
|
|
|
|
|
|
|
// [iterator.range]
|
|
|
|
#include <__iterator/access.h>
|
|
|
|
#include <__iterator/data.h>
|
|
|
|
#include <__iterator/empty.h>
|
|
|
|
#include <__iterator/reverse_access.h>
|
|
|
|
#include <__iterator/size.h>
|
|
|
|
|
|
|
|
// [deque.syn]
|
|
|
|
#include <compare>
|
|
|
|
#include <initializer_list>
|
|
|
|
|
2017-05-31 22:07:49 +00:00
|
|
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
2022-02-02 01:16:40 +00:00
|
|
|
# pragma GCC system_header
|
2017-05-31 22:07:49 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
_LIBCPP_PUSH_MACROS
|
|
|
|
#include <__undef_macros>
|
|
|
|
|
2011-11-29 16:45:27 +00:00
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
|
2017-01-04 23:56:00 +00:00
|
|
|
template <class _Tp, class _Allocator = allocator<_Tp> > class _LIBCPP_TEMPLATE_VIS deque;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2015-11-06 22:02:29 +00:00
|
|
|
template <class _ValueType, class _DiffType>
|
|
|
|
struct __deque_block_size {
|
|
|
|
static const _DiffType value = sizeof(_ValueType) < 256 ? 4096 / sizeof(_ValueType) : 16;
|
|
|
|
};
|
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _ValueType, class _Pointer, class _Reference, class _MapPointer,
|
2015-11-06 22:02:29 +00:00
|
|
|
class _DiffType, _DiffType _BS =
|
|
|
|
#ifdef _LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE
|
|
|
|
// Keep template parameter to avoid changing all template declarations thoughout
|
|
|
|
// this file.
|
|
|
|
0
|
|
|
|
#else
|
|
|
|
__deque_block_size<_ValueType, _DiffType>::value
|
|
|
|
#endif
|
|
|
|
>
|
2017-01-04 23:56:00 +00:00
|
|
|
class _LIBCPP_TEMPLATE_VIS __deque_iterator
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
typedef _MapPointer __map_iterator;
|
|
|
|
public:
|
|
|
|
typedef _Pointer pointer;
|
|
|
|
typedef _DiffType difference_type;
|
|
|
|
private:
|
|
|
|
__map_iterator __m_iter_;
|
|
|
|
pointer __ptr_;
|
|
|
|
|
2015-11-06 22:02:29 +00:00
|
|
|
static const difference_type __block_size;
|
2010-05-11 19:42:16 +00:00
|
|
|
public:
|
|
|
|
typedef _ValueType value_type;
|
|
|
|
typedef random_access_iterator_tag iterator_category;
|
|
|
|
typedef _Reference reference;
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_iterator() _NOEXCEPT
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 14
|
2013-08-06 16:14:36 +00:00
|
|
|
: __m_iter_(nullptr), __ptr_(nullptr)
|
|
|
|
#endif
|
|
|
|
{}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _Pp, class _Rp, class _MP, __enable_if_t<is_convertible<_Pp, pointer>::value, int> = 0>
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2023-08-18 20:08:04 +00:00
|
|
|
__deque_iterator(const __deque_iterator<value_type, _Pp, _Rp, _MP, difference_type, _BS>& __it) _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
: __m_iter_(__it.__m_iter_), __ptr_(__it.__ptr_) {}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI reference operator*() const {return *__ptr_;}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI pointer operator->() const {return __ptr_;}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_iterator& operator++()
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
if (++__ptr_ - *__m_iter_ == __block_size)
|
|
|
|
{
|
|
|
|
++__m_iter_;
|
|
|
|
__ptr_ = *__m_iter_;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_iterator operator++(int)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
__deque_iterator __tmp = *this;
|
|
|
|
++(*this);
|
|
|
|
return __tmp;
|
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_iterator& operator--()
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
if (__ptr_ == *__m_iter_)
|
|
|
|
{
|
|
|
|
--__m_iter_;
|
|
|
|
__ptr_ = *__m_iter_ + __block_size;
|
|
|
|
}
|
|
|
|
--__ptr_;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_iterator operator--(int)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
__deque_iterator __tmp = *this;
|
|
|
|
--(*this);
|
|
|
|
return __tmp;
|
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_iterator& operator+=(difference_type __n)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
if (__n != 0)
|
|
|
|
{
|
|
|
|
__n += __ptr_ - *__m_iter_;
|
|
|
|
if (__n > 0)
|
|
|
|
{
|
|
|
|
__m_iter_ += __n / __block_size;
|
|
|
|
__ptr_ = *__m_iter_ + __n % __block_size;
|
|
|
|
}
|
|
|
|
else // (__n < 0)
|
|
|
|
{
|
|
|
|
difference_type __z = __block_size - 1 - __n;
|
|
|
|
__m_iter_ -= __z / __block_size;
|
|
|
|
__ptr_ = *__m_iter_ + (__block_size - 1 - __z % __block_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
2010-08-22 00:02:43 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_iterator& operator-=(difference_type __n)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
return *this += -__n;
|
|
|
|
}
|
2010-08-22 00:02:43 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_iterator operator+(difference_type __n) const
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
__deque_iterator __t(*this);
|
|
|
|
__t += __n;
|
|
|
|
return __t;
|
|
|
|
}
|
2010-08-22 00:02:43 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_iterator operator-(difference_type __n) const
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
__deque_iterator __t(*this);
|
|
|
|
__t -= __n;
|
|
|
|
return __t;
|
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
friend __deque_iterator operator+(difference_type __n, const __deque_iterator& __it)
|
|
|
|
{return __it + __n;}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
friend difference_type operator-(const __deque_iterator& __x, const __deque_iterator& __y)
|
|
|
|
{
|
|
|
|
if (__x != __y)
|
|
|
|
return (__x.__m_iter_ - __y.__m_iter_) * __block_size
|
|
|
|
+ (__x.__ptr_ - *__x.__m_iter_)
|
|
|
|
- (__y.__ptr_ - *__y.__m_iter_);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI reference operator[](difference_type __n) const
|
2010-05-11 19:42:16 +00:00
|
|
|
{return *(*this + __n);}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI friend
|
2010-05-11 19:42:16 +00:00
|
|
|
bool operator==(const __deque_iterator& __x, const __deque_iterator& __y)
|
|
|
|
{return __x.__ptr_ == __y.__ptr_;}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI friend
|
2010-05-11 19:42:16 +00:00
|
|
|
bool operator!=(const __deque_iterator& __x, const __deque_iterator& __y)
|
|
|
|
{return !(__x == __y);}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI friend
|
2010-05-11 19:42:16 +00:00
|
|
|
bool operator<(const __deque_iterator& __x, const __deque_iterator& __y)
|
|
|
|
{return __x.__m_iter_ < __y.__m_iter_ ||
|
|
|
|
(__x.__m_iter_ == __y.__m_iter_ && __x.__ptr_ < __y.__ptr_);}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI friend
|
2010-05-11 19:42:16 +00:00
|
|
|
bool operator>(const __deque_iterator& __x, const __deque_iterator& __y)
|
|
|
|
{return __y < __x;}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI friend
|
2010-05-11 19:42:16 +00:00
|
|
|
bool operator<=(const __deque_iterator& __x, const __deque_iterator& __y)
|
|
|
|
{return !(__y < __x);}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI friend
|
2010-05-11 19:42:16 +00:00
|
|
|
bool operator>=(const __deque_iterator& __x, const __deque_iterator& __y)
|
|
|
|
{return !(__x < __y);}
|
|
|
|
|
|
|
|
private:
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI explicit __deque_iterator(__map_iterator __m, pointer __p) _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
: __m_iter_(__m), __ptr_(__p) {}
|
|
|
|
|
2017-01-04 23:56:00 +00:00
|
|
|
template <class _Tp, class _Ap> friend class _LIBCPP_TEMPLATE_VIS deque;
|
2011-11-29 18:15:50 +00:00
|
|
|
template <class _Vp, class _Pp, class _Rp, class _MP, class _Dp, _Dp>
|
2017-01-04 23:56:00 +00:00
|
|
|
friend class _LIBCPP_TEMPLATE_VIS __deque_iterator;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-11-20 22:16:20 +00:00
|
|
|
template <class>
|
|
|
|
friend struct __segmented_iterator_traits;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _ValueType, class _Pointer, class _Reference, class _MapPointer, class _DiffType, _DiffType _BlockSize>
|
|
|
|
struct __segmented_iterator_traits<
|
|
|
|
__deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer, _DiffType, _BlockSize> > {
|
|
|
|
private:
|
|
|
|
using _Iterator = __deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer, _DiffType, _BlockSize>;
|
|
|
|
|
|
|
|
public:
|
|
|
|
using __is_segmented_iterator = true_type;
|
|
|
|
using __segment_iterator = _MapPointer;
|
|
|
|
using __local_iterator = _Pointer;
|
|
|
|
|
|
|
|
static _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_Iterator __iter) { return __iter.__m_iter_; }
|
|
|
|
static _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_Iterator __iter) { return __iter.__ptr_; }
|
|
|
|
static _LIBCPP_HIDE_FROM_ABI __local_iterator __begin(__segment_iterator __iter) { return *__iter; }
|
|
|
|
|
|
|
|
static _LIBCPP_HIDE_FROM_ABI __local_iterator __end(__segment_iterator __iter) {
|
|
|
|
return *__iter + _Iterator::__block_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static _LIBCPP_HIDE_FROM_ABI _Iterator __compose(__segment_iterator __segment, __local_iterator __local) {
|
|
|
|
if (__local == __end(__segment)) {
|
|
|
|
++__segment;
|
|
|
|
return _Iterator(__segment, *__segment);
|
|
|
|
}
|
|
|
|
return _Iterator(__segment, __local);
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
};
|
|
|
|
|
2015-11-06 22:02:29 +00:00
|
|
|
template <class _ValueType, class _Pointer, class _Reference, class _MapPointer,
|
|
|
|
class _DiffType, _DiffType _BlockSize>
|
|
|
|
const _DiffType __deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer,
|
|
|
|
_DiffType, _BlockSize>::__block_size =
|
|
|
|
__deque_block_size<_ValueType, _DiffType>::value;
|
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
template <class _Tp, class _Allocator /*= allocator<_Tp>*/>
|
|
|
|
class _LIBCPP_TEMPLATE_VIS deque
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2018-05-18 23:44:13 +00:00
|
|
|
public:
|
2022-08-26 15:51:35 +00:00
|
|
|
// types:
|
2019-08-12 07:51:05 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
using value_type = _Tp;
|
2019-08-12 07:51:05 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
static_assert((is_same<typename _Allocator::value_type, value_type>::value),
|
|
|
|
"Allocator::value_type must be same type as value_type");
|
2019-08-12 07:51:05 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
using allocator_type = _Allocator;
|
|
|
|
using __alloc_traits = allocator_traits<allocator_type>;
|
2019-08-12 07:51:05 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
using size_type = typename __alloc_traits::size_type;
|
|
|
|
using difference_type = typename __alloc_traits::difference_type;
|
2019-08-12 07:51:05 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
using pointer = typename __alloc_traits::pointer;
|
|
|
|
using const_pointer = typename __alloc_traits::const_pointer;
|
2019-08-12 07:51:05 +00:00
|
|
|
|
2022-10-08 20:17:32 +00:00
|
|
|
using __pointer_allocator = __rebind_alloc<__alloc_traits, pointer>;
|
|
|
|
using __const_pointer_allocator = __rebind_alloc<__alloc_traits, const_pointer>;
|
2022-08-26 15:51:35 +00:00
|
|
|
using __map = __split_buffer<pointer, __pointer_allocator>;
|
|
|
|
using __map_alloc_traits = allocator_traits<__pointer_allocator>;
|
|
|
|
using __map_pointer = typename __map_alloc_traits::pointer;
|
|
|
|
using __map_const_pointer = typename allocator_traits<__const_pointer_allocator>::const_pointer;
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
using __map_const_iterator = typename __map::const_iterator;
|
2019-08-12 07:51:05 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
using reference = value_type&;
|
|
|
|
using const_reference = const value_type&;
|
2019-08-12 07:51:05 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
using iterator = __deque_iterator<value_type, pointer, reference, __map_pointer, difference_type>;
|
|
|
|
using const_iterator =
|
|
|
|
__deque_iterator<value_type, const_pointer, const_reference, __map_const_pointer, difference_type>;
|
|
|
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
|
|
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-10-08 20:17:32 +00:00
|
|
|
static_assert(is_same<allocator_type, __rebind_alloc<__alloc_traits, value_type> >::value,
|
|
|
|
"[allocator.requirements] states that rebinding an allocator to the same type should result in the "
|
|
|
|
"original allocator");
|
2022-08-26 15:51:35 +00:00
|
|
|
static_assert(is_nothrow_default_constructible<allocator_type>::value ==
|
|
|
|
is_nothrow_default_constructible<__pointer_allocator>::value,
|
|
|
|
"rebinding an allocator should not change excpetion guarantees");
|
|
|
|
static_assert(is_nothrow_move_constructible<allocator_type>::value ==
|
|
|
|
is_nothrow_move_constructible<typename __map::allocator_type>::value,
|
|
|
|
"rebinding an allocator should not change excpetion guarantees");
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
private:
|
|
|
|
struct __deque_block_range {
|
2022-08-21 00:03:35 +00:00
|
|
|
explicit _LIBCPP_HIDE_FROM_ABI
|
|
|
|
__deque_block_range(pointer __b, pointer __e) _NOEXCEPT : __begin_(__b), __end_(__e) {}
|
2022-08-26 15:51:35 +00:00
|
|
|
const pointer __begin_;
|
|
|
|
const pointer __end_;
|
|
|
|
};
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
struct __deque_range {
|
|
|
|
iterator __pos_;
|
|
|
|
const iterator __end_;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_range(iterator __pos, iterator __e) _NOEXCEPT
|
2022-08-26 15:51:35 +00:00
|
|
|
: __pos_(__pos), __end_(__e) {}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
explicit _LIBCPP_HIDE_FROM_ABI operator bool() const _NOEXCEPT {
|
2022-08-26 15:51:35 +00:00
|
|
|
return __pos_ != __end_;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_range begin() const {
|
2022-08-26 15:51:35 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2015-11-06 22:02:29 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_range end() const {
|
2022-08-26 15:51:35 +00:00
|
|
|
return __deque_range(__end_, __end_);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_block_range operator*() const _NOEXCEPT {
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__pos_.__m_iter_ == __end_.__m_iter_) {
|
|
|
|
return __deque_block_range(__pos_.__ptr_, __end_.__ptr_);
|
|
|
|
}
|
|
|
|
return __deque_block_range(__pos_.__ptr_, *__pos_.__m_iter_ + __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI __deque_range& operator++() _NOEXCEPT {
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__pos_.__m_iter_ == __end_.__m_iter_) {
|
|
|
|
__pos_ = __end_;
|
|
|
|
} else {
|
|
|
|
++__pos_.__m_iter_;
|
|
|
|
__pos_.__ptr_ = *__pos_.__m_iter_;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI friend bool operator==(__deque_range const& __lhs, __deque_range const& __rhs) {
|
|
|
|
return __lhs.__pos_ == __rhs.__pos_;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI friend bool operator!=(__deque_range const& __lhs, __deque_range const& __rhs) {
|
|
|
|
return !(__lhs == __rhs);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
};
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
struct _ConstructTransaction {
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI _ConstructTransaction(deque* __db, __deque_block_range& __r)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __pos_(__r.__begin_), __end_(__r.__end_), __begin_(__r.__begin_), __base_(__db) {}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() {
|
2022-08-26 15:51:35 +00:00
|
|
|
__base_->__size() += (__pos_ - __begin_);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
pointer __pos_;
|
|
|
|
const pointer __end_;
|
|
|
|
private:
|
|
|
|
const pointer __begin_;
|
|
|
|
deque* const __base_;
|
|
|
|
};
|
2010-08-22 00:02:43 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
static const difference_type __block_size;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
__map __map_;
|
|
|
|
size_type __start_;
|
|
|
|
__compressed_pair<size_type, allocator_type> __size_;
|
2015-11-26 01:24:04 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
public:
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
// construct/copy/destroy:
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2022-08-26 15:51:35 +00:00
|
|
|
deque() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
: __start_(0), __size_(0, __default_init_tag()) {
|
|
|
|
__annotate_new(0);
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI ~deque() {
|
|
|
|
clear();
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_delete();
|
2022-08-26 15:51:35 +00:00
|
|
|
typename __map::iterator __i = __map_.begin();
|
|
|
|
typename __map::iterator __e = __map_.end();
|
|
|
|
for (; __i != __e; ++__i)
|
|
|
|
__alloc_traits::deallocate(__alloc(), *__i, __block_size);
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI explicit deque(const allocator_type& __a)
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
: __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
|
|
|
|
__annotate_new(0);
|
|
|
|
}
|
2019-08-12 07:51:05 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
explicit _LIBCPP_HIDE_FROM_ABI deque(size_type __n);
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 14
|
2022-08-21 00:03:35 +00:00
|
|
|
explicit _LIBCPP_HIDE_FROM_ABI deque(size_type __n, const _Allocator& __a);
|
2013-09-07 16:16:19 +00:00
|
|
|
#endif
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI deque(size_type __n, const value_type& __v);
|
[libcxx][NFC] Make sequence containers slightly more SFINAE-friendly during CTAD.
Disable the constructors taking `(size_type, const value_type&,
allocator_type)` if `allocator_type` is not a valid allocator.
Otherwise, these constructors are considered when resolving e.g.
`(int*, int*, NotAnAllocator())`, leading to a hard error during
instantiation. A hard error makes the Standard's requirement to not
consider deduction guides of the form `(Iterator, Iterator,
BadAllocator)` during overload resolution essentially non-functional.
The previous approach was to SFINAE away `allocator_traits`. This patch
SFINAEs away the specific constructors instead, for consistency with
`basic_string` -- see [LWG3076](wg21.link/lwg3076) which describes
a very similar problem for strings (note, however, that unlike LWG3076,
no valid constructor call is affected by the bad instantiation).
Differential Revision: https://reviews.llvm.org/D114311
2021-12-01 19:55:46 +00:00
|
|
|
|
|
|
|
template <class = __enable_if_t<__is_allocator<_Allocator>::value> >
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI deque(size_type __n, const value_type& __v, const allocator_type& __a)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
|
[libcxx][NFC] Make sequence containers slightly more SFINAE-friendly during CTAD.
Disable the constructors taking `(size_type, const value_type&,
allocator_type)` if `allocator_type` is not a valid allocator.
Otherwise, these constructors are considered when resolving e.g.
`(int*, int*, NotAnAllocator())`, leading to a hard error during
instantiation. A hard error makes the Standard's requirement to not
consider deduction guides of the form `(Iterator, Iterator,
BadAllocator)` during overload resolution essentially non-functional.
The previous approach was to SFINAE away `allocator_traits`. This patch
SFINAEs away the specific constructors instead, for consistency with
`basic_string` -- see [LWG3076](wg21.link/lwg3076) which describes
a very similar problem for strings (note, however, that unlike LWG3076,
no valid constructor call is affected by the bad instantiation).
Differential Revision: https://reviews.llvm.org/D114311
2021-12-01 19:55:46 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
[libcxx][NFC] Make sequence containers slightly more SFINAE-friendly during CTAD.
Disable the constructors taking `(size_type, const value_type&,
allocator_type)` if `allocator_type` is not a valid allocator.
Otherwise, these constructors are considered when resolving e.g.
`(int*, int*, NotAnAllocator())`, leading to a hard error during
instantiation. A hard error makes the Standard's requirement to not
consider deduction guides of the form `(Iterator, Iterator,
BadAllocator)` during overload resolution essentially non-functional.
The previous approach was to SFINAE away `allocator_traits`. This patch
SFINAEs away the specific constructors instead, for consistency with
`basic_string` -- see [LWG3076](wg21.link/lwg3076) which describes
a very similar problem for strings (note, however, that unlike LWG3076,
no valid constructor call is affected by the bad instantiation).
Differential Revision: https://reviews.llvm.org/D114311
2021-12-01 19:55:46 +00:00
|
|
|
if (__n > 0)
|
|
|
|
__append(__n, __v);
|
|
|
|
}
|
|
|
|
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI deque(_InputIter __f, _InputIter __l);
|
|
|
|
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI deque(_InputIter __f, _InputIter __l, const allocator_type& __a);
|
2023-05-17 07:48:24 +00:00
|
|
|
|
|
|
|
#if _LIBCPP_STD_VER >= 23
|
|
|
|
template <_ContainerCompatibleRange<_Tp> _Range>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI deque(from_range_t, _Range&& __range,
|
|
|
|
const allocator_type& __a = allocator_type())
|
|
|
|
: __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
|
|
|
|
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
|
|
|
|
__append_with_size(ranges::begin(__range), ranges::distance(__range));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
for (auto&& __e : __range) {
|
|
|
|
emplace_back(std::forward<decltype(__e)>(__e));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI deque(const deque& __c);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI deque(const deque& __c, const __type_identity_t<allocator_type>& __a);
|
2017-04-16 03:17:01 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI deque& operator=(const deque& __c);
|
2017-04-16 03:17:01 +00:00
|
|
|
|
|
|
|
#ifndef _LIBCPP_CXX03_LANG
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI deque(initializer_list<value_type> __il);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI deque(initializer_list<value_type> __il, const allocator_type& __a);
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
deque& operator=(initializer_list<value_type> __il) {assign(__il); return *this;}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2022-08-26 15:51:35 +00:00
|
|
|
deque(deque&& __c) _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2022-03-18 16:49:02 +00:00
|
|
|
deque(deque&& __c, const __type_identity_t<allocator_type>& __a);
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 20:00:14 +00:00
|
|
|
deque& operator=(deque&& __c)
|
2011-06-02 21:38:57 +00:00
|
|
|
_NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value &&
|
|
|
|
is_nothrow_move_assignable<allocator_type>::value);
|
2017-04-16 03:17:01 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2017-04-16 03:17:01 +00:00
|
|
|
void assign(initializer_list<value_type> __il) {assign(__il.begin(), __il.end());}
|
2021-04-20 16:03:32 +00:00
|
|
|
#endif // _LIBCPP_CXX03_LANG
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value &&
|
|
|
|
!__has_random_access_iterator_category<_InputIter>::value, int> = 0>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void assign(_InputIter __f, _InputIter __l);
|
|
|
|
template <class _RAIter, __enable_if_t<__has_random_access_iterator_category<_RAIter>::value, int> = 0>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void assign(_RAIter __f, _RAIter __l);
|
2023-05-17 07:48:24 +00:00
|
|
|
|
|
|
|
#if _LIBCPP_STD_VER >= 23
|
|
|
|
template <_ContainerCompatibleRange<_Tp> _Range>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void assign_range(_Range&& __range) {
|
|
|
|
if constexpr (ranges::random_access_range<_Range>) {
|
|
|
|
auto __n = static_cast<size_type>(ranges::distance(__range));
|
|
|
|
__assign_with_size_random_access(ranges::begin(__range), __n);
|
|
|
|
|
|
|
|
} else if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
|
|
|
|
auto __n = static_cast<size_type>(ranges::distance(__range));
|
|
|
|
__assign_with_size(ranges::begin(__range), __n);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
__assign_with_sentinel(ranges::begin(__range), ranges::end(__range));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const value_type& __v);
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
allocator_type get_allocator() const _NOEXCEPT;
|
2022-08-26 15:51:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __size_.second(); }
|
|
|
|
_LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __size_.second(); }
|
|
|
|
|
|
|
|
// iterators:
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT {
|
|
|
|
__map_pointer __mp = __map_.begin() + __start_ / __block_size;
|
|
|
|
return iterator(__mp, __map_.empty() ? 0 : *__mp + __start_ % __block_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
|
|
|
|
__map_const_pointer __mp =
|
|
|
|
static_cast<__map_const_pointer>(__map_.begin() + __start_ / __block_size);
|
|
|
|
return const_iterator(__mp, __map_.empty() ? 0 : *__mp + __start_ % __block_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT {
|
|
|
|
size_type __p = size() + __start_;
|
|
|
|
__map_pointer __mp = __map_.begin() + __p / __block_size;
|
|
|
|
return iterator(__mp, __map_.empty() ? 0 : *__mp + __p % __block_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT {
|
|
|
|
size_type __p = size() + __start_;
|
|
|
|
__map_const_pointer __mp = static_cast<__map_const_pointer>(__map_.begin() + __p / __block_size);
|
|
|
|
return const_iterator(__mp, __map_.empty() ? 0 : *__mp + __p % __block_size);
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
reverse_iterator rbegin() _NOEXCEPT
|
2022-08-26 15:51:35 +00:00
|
|
|
{return reverse_iterator(end());}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
const_reverse_iterator rbegin() const _NOEXCEPT
|
2022-08-26 15:51:35 +00:00
|
|
|
{return const_reverse_iterator(end());}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
reverse_iterator rend() _NOEXCEPT
|
2022-08-26 15:51:35 +00:00
|
|
|
{return reverse_iterator(begin());}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
const_reverse_iterator rend() const _NOEXCEPT
|
2022-08-26 15:51:35 +00:00
|
|
|
{return const_reverse_iterator(begin());}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
const_iterator cbegin() const _NOEXCEPT
|
2022-08-26 15:51:35 +00:00
|
|
|
{return begin();}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
const_iterator cend() const _NOEXCEPT
|
2022-08-26 15:51:35 +00:00
|
|
|
{return end();}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
const_reverse_iterator crbegin() const _NOEXCEPT
|
2022-08-26 15:51:35 +00:00
|
|
|
{return const_reverse_iterator(end());}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
const_reverse_iterator crend() const _NOEXCEPT
|
2022-08-26 15:51:35 +00:00
|
|
|
{return const_reverse_iterator(begin());}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
// capacity:
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type size() const _NOEXCEPT {return __size();}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI size_type& __size() _NOEXCEPT { return __size_.first(); }
|
|
|
|
_LIBCPP_HIDE_FROM_ABI const size_type& __size() const _NOEXCEPT { return __size_.first(); }
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
size_type max_size() const _NOEXCEPT
|
[libc++] Consistently replace `std::` qualification with `_VSTD::` or nothing. NFCI.
I used a lot of `git grep` to find places where `std::` was being used
outside of comments and assert-messages. There were three outcomes:
- Qualified function calls, e.g. `std::move` becomes `_VSTD::move`.
This is the most common case.
- Typenames that don't need qualification, e.g. `std::allocator` becomes `allocator`.
Leaving these as `_VSTD::allocator` would also be fine, but I decided
that removing the qualification is more consistent with existing practice.
- Names that specifically need un-versioned `std::` qualification,
or that I wasn't sure about. For example, I didn't touch any code in
<atomic>, <math.h>, <new>, or any ext/ or experimental/ headers;
and I didn't touch any instances of `std::type_info`.
In some deduction guides, we were accidentally using `class Alloc = typename std::allocator<T>`,
despite `std::allocator<T>`'s type-ness not being template-dependent.
Because `std::allocator` is a qualified name, this did parse as we intended;
but what we meant was simply `class Alloc = allocator<T>`.
Differential Revision: https://reviews.llvm.org/D92250
2020-11-27 16:02:06 +00:00
|
|
|
{return std::min<size_type>(
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::max_size(__alloc()),
|
2016-11-23 01:18:56 +00:00
|
|
|
numeric_limits<difference_type>::max());}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void resize(size_type __n);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void resize(size_type __n, const value_type& __v);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT;
|
|
|
|
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI
|
2022-08-26 15:51:35 +00:00
|
|
|
bool empty() const _NOEXCEPT {return size() == 0;}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
// element access:
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-03-14 21:56:57 +00:00
|
|
|
reference operator[](size_type __i) _NOEXCEPT;
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-03-14 21:56:57 +00:00
|
|
|
const_reference operator[](size_type __i) const _NOEXCEPT;
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
reference at(size_type __i);
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
const_reference at(size_type __i) const;
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-03-19 03:30:07 +00:00
|
|
|
reference front() _NOEXCEPT;
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-03-19 03:30:07 +00:00
|
|
|
const_reference front() const _NOEXCEPT;
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-03-19 03:30:07 +00:00
|
|
|
reference back() _NOEXCEPT;
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-03-19 03:30:07 +00:00
|
|
|
const_reference back() const _NOEXCEPT;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
// 23.2.2.3 modifiers:
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void push_front(const value_type& __v);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void push_back(const value_type& __v);
|
2017-04-16 03:17:01 +00:00
|
|
|
#ifndef _LIBCPP_CXX03_LANG
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 17
|
2022-08-21 00:03:35 +00:00
|
|
|
template <class... _Args> _LIBCPP_HIDE_FROM_ABI reference emplace_front(_Args&&... __args);
|
|
|
|
template <class... _Args> _LIBCPP_HIDE_FROM_ABI reference emplace_back (_Args&&... __args);
|
2017-01-24 23:09:12 +00:00
|
|
|
#else
|
2022-08-21 00:03:35 +00:00
|
|
|
template <class... _Args> _LIBCPP_HIDE_FROM_ABI void emplace_front(_Args&&... __args);
|
|
|
|
template <class... _Args> _LIBCPP_HIDE_FROM_ABI void emplace_back (_Args&&... __args);
|
2017-01-24 23:09:12 +00:00
|
|
|
#endif
|
2022-08-21 00:03:35 +00:00
|
|
|
template <class... _Args> _LIBCPP_HIDE_FROM_ABI iterator emplace(const_iterator __p, _Args&&... __args);
|
2017-04-16 03:17:01 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void push_front(value_type&& __v);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void push_back(value_type&& __v);
|
2023-05-17 07:48:24 +00:00
|
|
|
|
|
|
|
#if _LIBCPP_STD_VER >= 23
|
|
|
|
template <_ContainerCompatibleRange<_Tp> _Range>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void prepend_range(_Range&& __range) {
|
|
|
|
insert_range(begin(), std::forward<_Range>(__range));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <_ContainerCompatibleRange<_Tp> _Range>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void append_range(_Range&& __range) {
|
|
|
|
insert_range(end(), std::forward<_Range>(__range));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, value_type&& __v);
|
2017-04-16 03:17:01 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2017-04-16 03:17:01 +00:00
|
|
|
iterator insert(const_iterator __p, initializer_list<value_type> __il)
|
|
|
|
{return insert(__p, __il.begin(), __il.end());}
|
2021-04-20 16:03:32 +00:00
|
|
|
#endif // _LIBCPP_CXX03_LANG
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, const value_type& __v);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, size_type __n, const value_type& __v);
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _InputIter, __enable_if_t<__has_exactly_input_iterator_category<_InputIter>::value, int> = 0>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, _InputIter __f, _InputIter __l);
|
|
|
|
template <class _ForwardIterator, __enable_if_t<__has_exactly_forward_iterator_category<_ForwardIterator>::value, int> = 0>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, _ForwardIterator __f, _ForwardIterator __l);
|
|
|
|
template <class _BiIter, __enable_if_t<__has_bidirectional_iterator_category<_BiIter>::value, int> = 0>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, _BiIter __f, _BiIter __l);
|
2017-04-16 03:17:01 +00:00
|
|
|
|
2023-05-17 07:48:24 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 23
|
|
|
|
template <_ContainerCompatibleRange<_Tp> _Range>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
iterator insert_range(const_iterator __position, _Range&& __range) {
|
|
|
|
if constexpr (ranges::bidirectional_range<_Range>) {
|
|
|
|
auto __n = static_cast<size_type>(ranges::distance(__range));
|
|
|
|
return __insert_bidirectional(__position, ranges::begin(__range), ranges::end(__range), __n);
|
|
|
|
|
|
|
|
} else if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
|
|
|
|
auto __n = static_cast<size_type>(ranges::distance(__range));
|
|
|
|
return __insert_with_size(__position, ranges::begin(__range), __n);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
return __insert_with_sentinel(__position, ranges::begin(__range), ranges::end(__range));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void pop_front();
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void pop_back();
|
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l);
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 20:00:14 +00:00
|
|
|
void swap(deque& __c)
|
2015-07-13 20:04:56 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 14
|
|
|
|
_NOEXCEPT;
|
|
|
|
#else
|
2011-06-02 20:00:14 +00:00
|
|
|
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
|
|
|
|
__is_nothrow_swappable<allocator_type>::value);
|
2015-07-13 20:04:56 +00:00
|
|
|
#endif
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-06-02 16:10:22 +00:00
|
|
|
void clear() _NOEXCEPT;
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2022-08-26 15:51:35 +00:00
|
|
|
bool __invariants() const {
|
|
|
|
if (!__map_.__invariants())
|
|
|
|
return false;
|
|
|
|
if (__map_.size() >= size_type(-1) / __block_size)
|
|
|
|
return false;
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
for (__map_const_iterator __i = __map_.begin(), __e = __map_.end();
|
2022-08-26 15:51:35 +00:00
|
|
|
__i != __e; ++__i)
|
|
|
|
if (*__i == nullptr)
|
|
|
|
return false;
|
|
|
|
if (__map_.size() != 0)
|
|
|
|
{
|
|
|
|
if (size() >= __map_.size() * __block_size)
|
|
|
|
return false;
|
|
|
|
if (__start_ >= __map_.size() * __block_size - size())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (size() != 0)
|
|
|
|
return false;
|
|
|
|
if (__start_ != 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2022-08-26 15:51:35 +00:00
|
|
|
void __move_assign_alloc(deque& __c)
|
|
|
|
_NOEXCEPT_(!__alloc_traits::propagate_on_container_move_assignment::value ||
|
|
|
|
is_nothrow_move_assignable<allocator_type>::value)
|
|
|
|
{__move_assign_alloc(__c, integral_constant<bool,
|
|
|
|
__alloc_traits::propagate_on_container_move_assignment::value>());}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2022-08-26 15:51:35 +00:00
|
|
|
void __move_assign_alloc(deque& __c, true_type)
|
|
|
|
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
|
|
|
|
{
|
|
|
|
__alloc() = std::move(__c.__alloc());
|
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2022-08-26 15:51:35 +00:00
|
|
|
void __move_assign_alloc(deque&, false_type) _NOEXCEPT
|
|
|
|
{}
|
2019-08-01 23:11:18 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2022-08-26 15:51:35 +00:00
|
|
|
void __move_assign(deque& __c)
|
|
|
|
_NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value &&
|
|
|
|
is_nothrow_move_assignable<allocator_type>::value)
|
|
|
|
{
|
|
|
|
__map_ = std::move(__c.__map_);
|
|
|
|
__start_ = __c.__start_;
|
|
|
|
__size() = __c.size();
|
|
|
|
__move_assign_alloc(__c);
|
|
|
|
__c.__start_ = __c.__size() = 0;
|
|
|
|
}
|
2013-06-23 21:17:24 +00:00
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
static size_type __recommend_blocks(size_type __n)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
return __n / __block_size + (__n % __block_size != 0);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
size_type __capacity() const
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
return __map_.size() == 0 ? 0 : __map_.size() * __block_size - 1;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-08-01 23:11:18 +00:00
|
|
|
size_type __block_count() const
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
return __map_.size();
|
2019-08-01 23:11:18 +00:00
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
size_type __front_spare() const
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
return __start_;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-08-01 23:11:18 +00:00
|
|
|
size_type __front_spare_blocks() const {
|
2022-08-26 15:51:35 +00:00
|
|
|
return __front_spare() / __block_size;
|
2019-08-01 23:11:18 +00:00
|
|
|
}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
size_type __back_spare() const
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
return __capacity() - (__start_ + size());
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-08-01 23:11:18 +00:00
|
|
|
size_type __back_spare_blocks() const {
|
2022-08-26 15:51:35 +00:00
|
|
|
return __back_spare() / __block_size;
|
2019-08-01 23:11:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
enum __asan_annotation_type {
|
|
|
|
__asan_unposion,
|
|
|
|
__asan_poison
|
|
|
|
};
|
|
|
|
|
|
|
|
enum __asan_annotation_place {
|
|
|
|
__asan_front_moved,
|
|
|
|
__asan_back_moved,
|
|
|
|
};
|
|
|
|
|
|
|
|
// The following functions are no-ops outside of AddressSanitizer mode.
|
2023-07-24 17:57:22 +00:00
|
|
|
// We call annotations for every allocator, unless explicitly disabled.
|
|
|
|
//
|
|
|
|
// To disable annotations for a particular allocator, change value of
|
|
|
|
// __asan_annotate_container_with_allocator to false.
|
|
|
|
// For more details, see the "Using libc++" documentation page or
|
|
|
|
// the documentation for __sanitizer_annotate_contiguous_container.
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void __annotate_double_ended_contiguous_container(
|
2023-12-13 23:05:36 +00:00
|
|
|
const void* __beg,
|
|
|
|
const void* __end,
|
|
|
|
const void* __old_con_beg,
|
|
|
|
const void* __old_con_end,
|
|
|
|
const void* __new_con_beg,
|
|
|
|
const void* __new_con_end) const {
|
|
|
|
(void)__beg;
|
|
|
|
(void)__end;
|
|
|
|
(void)__old_con_beg;
|
|
|
|
(void)__old_con_end;
|
|
|
|
(void)__new_con_beg;
|
|
|
|
(void)__new_con_end;
|
2023-12-05 18:27:08 +00:00
|
|
|
#ifndef _LIBCPP_HAS_NO_ASAN
|
2023-07-18 19:15:13 +00:00
|
|
|
if (__beg != nullptr && __asan_annotate_container_with_allocator<_Allocator>::value)
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__sanitizer_annotate_double_ended_contiguous_container(
|
|
|
|
__beg, __end, __old_con_beg, __old_con_end, __new_con_beg, __new_con_end);
|
2023-12-05 18:27:08 +00:00
|
|
|
#endif
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2023-12-05 18:27:08 +00:00
|
|
|
void __annotate_from_to(
|
2023-12-13 23:05:36 +00:00
|
|
|
size_type __beg,
|
|
|
|
size_type __end,
|
|
|
|
__asan_annotation_type __annotation_type,
|
|
|
|
__asan_annotation_place __place) const _NOEXCEPT {
|
|
|
|
(void)__beg;
|
|
|
|
(void)__end;
|
|
|
|
(void)__annotation_type;
|
|
|
|
(void)__place;
|
2023-12-05 18:27:08 +00:00
|
|
|
#ifndef _LIBCPP_HAS_NO_ASAN
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
// __beg - index of the first item to annotate
|
|
|
|
// __end - index behind the last item to annotate (so last item + 1)
|
|
|
|
// __annotation_type - __asan_unposion or __asan_poison
|
|
|
|
// __place - __asan_front_moved or __asan_back_moved
|
|
|
|
// Note: All indexes in __map_
|
|
|
|
if (__beg == __end)
|
|
|
|
return;
|
|
|
|
// __annotations_beg_map - first chunk which annotations we want to modify
|
|
|
|
// __annotations_end_map - last chunk which annotations we want to modify
|
|
|
|
// NOTE: if __end % __block_size == 0, __annotations_end_map points at the next block, which may not exist
|
|
|
|
__map_const_iterator __annotations_beg_map = __map_.begin() + __beg / __block_size;
|
|
|
|
__map_const_iterator __annotations_end_map = __map_.begin() + __end / __block_size;
|
|
|
|
|
|
|
|
bool const __poisoning = __annotation_type == __asan_poison;
|
|
|
|
// __old_c_beg_index - index of the first element in old container
|
|
|
|
// __old_c_end_index - index of the end of old container (last + 1)
|
|
|
|
// Note: may be outside the area we are annotating
|
|
|
|
size_t __old_c_beg_index = (__poisoning && __place == __asan_front_moved) ? __beg : __start_;
|
|
|
|
size_t __old_c_end_index = (__poisoning && __place == __asan_back_moved) ? __end : __start_ + size();
|
|
|
|
bool const __front = __place == __asan_front_moved;
|
|
|
|
|
|
|
|
if (__poisoning && empty()) {
|
|
|
|
// Special case: we shouldn't trust __start_
|
|
|
|
__old_c_beg_index = __beg;
|
|
|
|
__old_c_end_index = __end;
|
|
|
|
}
|
|
|
|
// __old_c_beg_map - memory block (chunk) with first element
|
|
|
|
// __old_c_end_map - memory block (chunk) with end of old container
|
|
|
|
// Note: if __old_c_end_index % __block_size == 0, __old_c_end_map points at the next block,
|
|
|
|
// which may not exist
|
|
|
|
__map_const_iterator __old_c_beg_map = __map_.begin() + __old_c_beg_index / __block_size;
|
|
|
|
__map_const_iterator __old_c_end_map = __map_.begin() + __old_c_end_index / __block_size;
|
|
|
|
|
|
|
|
// One edge (front/end) of the container was moved and one was not modified.
|
|
|
|
// __new_edge_index - index of new edge
|
|
|
|
// __new_edge_map - memory block (chunk) with new edge, it always equals to
|
|
|
|
// __annotations_beg_map or __annotations_end_map
|
|
|
|
// __old_edge_map - memory block (chunk) with old edge, it always equals to
|
|
|
|
// __old_c_beg_map or __old_c_end_map
|
|
|
|
size_t __new_edge_index = (__poisoning ^ __front) ? __beg : __end;
|
|
|
|
__map_const_iterator __new_edge_map = __map_.begin() + __new_edge_index / __block_size;
|
|
|
|
__map_const_iterator __old_edge_map = __front ? __old_c_end_map : __old_c_beg_map;
|
|
|
|
|
|
|
|
// We iterate over map pointers (chunks) and fully poison all memory blocks between the first and the last.
|
|
|
|
// First and last chunk may be partially poisoned.
|
|
|
|
// __annotate_end_map may point at not existing chunk, therefore we have to have a check for it.
|
|
|
|
for (__map_const_iterator __map_it = __annotations_beg_map; __map_it <= __annotations_end_map; ++__map_it) {
|
|
|
|
if (__map_it == __annotations_end_map && __end % __block_size == 0)
|
|
|
|
// Chunk may not exist, but nothing to do here anyway
|
|
|
|
break;
|
|
|
|
|
|
|
|
// The beginning and the end of the current memory block
|
|
|
|
const void* __mem_beg = std::__to_address(*__map_it);
|
|
|
|
const void* __mem_end = std::__to_address(*__map_it + __block_size);
|
|
|
|
|
|
|
|
// The beginning of memory-in-use in the memory block before container modification
|
|
|
|
const void* __old_beg =
|
|
|
|
(__map_it == __old_c_beg_map) ? std::__to_address(*__map_it + (__old_c_beg_index % __block_size)) : __mem_beg;
|
|
|
|
|
|
|
|
// The end of memory-in-use in the memory block before container modification
|
|
|
|
const void* __old_end;
|
|
|
|
if (__map_it < __old_c_beg_map || __map_it > __old_c_end_map || (!__poisoning && empty()))
|
|
|
|
__old_end = __old_beg;
|
|
|
|
else
|
|
|
|
__old_end = (__map_it == __old_c_end_map) ? std::__to_address(*__map_it + (__old_c_end_index % __block_size))
|
|
|
|
: __mem_end;
|
|
|
|
|
|
|
|
// New edge of the container in current memory block
|
|
|
|
// If the edge is in a different chunk it points on corresponding end of the memory block
|
|
|
|
const void* __new_edge;
|
|
|
|
if (__map_it == __new_edge_map)
|
|
|
|
__new_edge = std::__to_address(*__map_it + (__new_edge_index % __block_size));
|
|
|
|
else
|
|
|
|
__new_edge = (__poisoning ^ __front) ? __mem_beg : __mem_end;
|
|
|
|
|
|
|
|
// Not modified edge of the container
|
|
|
|
// If the edge is in a different chunk it points on corresponding end of the memory block
|
|
|
|
const void* __old_edge;
|
|
|
|
if (__map_it == __old_edge_map)
|
|
|
|
__old_edge = __front ? __old_end : __old_beg;
|
|
|
|
else
|
|
|
|
__old_edge = __front ? __mem_end : __mem_beg;
|
|
|
|
|
|
|
|
// __new_beg - the beginning of memory-in-use in the memory block after container modification
|
|
|
|
// __new_end - the end of memory-in-use in the memory block after container modification
|
|
|
|
const void* __new_beg = __front ? __new_edge : __old_edge;
|
|
|
|
const void* __new_end = __front ? __old_edge : __new_edge;
|
|
|
|
|
|
|
|
__annotate_double_ended_contiguous_container(__mem_beg, __mem_end, __old_beg, __old_end, __new_beg, __new_end);
|
|
|
|
}
|
2023-12-05 18:27:08 +00:00
|
|
|
#endif // !_LIBCPP_HAS_NO_ASAN
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __annotate_new(size_type __current_size) const _NOEXCEPT {
|
|
|
|
if (__current_size == 0)
|
|
|
|
__annotate_from_to(0, __map_.size() * __block_size, __asan_poison, __asan_back_moved);
|
|
|
|
else {
|
|
|
|
__annotate_from_to(0, __start_, __asan_poison, __asan_front_moved);
|
|
|
|
__annotate_from_to(__start_ + __current_size, __map_.size() * __block_size, __asan_poison, __asan_back_moved);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __annotate_delete() const _NOEXCEPT {
|
|
|
|
if (empty()) {
|
|
|
|
for(size_t __i = 0; __i < __map_.size(); ++__i) {
|
|
|
|
__annotate_whole_block(__i, __asan_unposion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
__annotate_from_to(0, __start_, __asan_unposion, __asan_front_moved);
|
|
|
|
__annotate_from_to(__start_ + size(), __map_.size() * __block_size, __asan_unposion, __asan_back_moved);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __annotate_increase_front(size_type __n) const _NOEXCEPT {
|
|
|
|
__annotate_from_to(__start_ - __n, __start_, __asan_unposion, __asan_front_moved);
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __annotate_increase_back(size_type __n) const _NOEXCEPT {
|
|
|
|
__annotate_from_to(__start_ + size(), __start_ + size() + __n, __asan_unposion, __asan_back_moved);
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __annotate_shrink_front(size_type __old_size, size_type __old_start) const _NOEXCEPT {
|
|
|
|
__annotate_from_to(__old_start, __old_start + (__old_size - size()), __asan_poison, __asan_front_moved);
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __annotate_shrink_back(size_type __old_size, size_type __old_start) const _NOEXCEPT {
|
|
|
|
__annotate_from_to(__old_start + size(), __old_start + __old_size, __asan_poison, __asan_back_moved);
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __annotate_poison_block(const void *__beginning, const void *__end) const _NOEXCEPT {
|
|
|
|
__annotate_double_ended_contiguous_container(__beginning, __end, __beginning, __end, __end, __end);
|
|
|
|
}
|
|
|
|
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __annotate_whole_block(size_t __block_index, __asan_annotation_type __annotation_type) const _NOEXCEPT {
|
|
|
|
__map_const_iterator __block_it = __map_.begin() + __block_index;
|
|
|
|
const void* __block_start = std::__to_address(*__block_it);
|
|
|
|
const void* __block_end = std::__to_address(*__block_it + __block_size);
|
|
|
|
|
|
|
|
if(__annotation_type == __asan_poison)
|
|
|
|
__annotate_poison_block(__block_start, __block_end);
|
|
|
|
else {
|
|
|
|
__annotate_double_ended_contiguous_container(
|
|
|
|
__block_start, __block_end, __block_start, __block_start, __block_start, __block_end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_ASAN)
|
|
|
|
|
|
|
|
public:
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
bool __verify_asan_annotations() const _NOEXCEPT {
|
|
|
|
// This function tests deque object annotations.
|
|
|
|
if (empty()) {
|
|
|
|
for (__map_const_iterator __it = __map_.begin(); __it != __map_.end(); ++__it) {
|
|
|
|
if (!__sanitizer_verify_double_ended_contiguous_container(
|
|
|
|
std::__to_address(*__it),
|
|
|
|
std::__to_address(*__it),
|
|
|
|
std::__to_address(*__it),
|
|
|
|
std::__to_address(*__it + __block_size)))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_type __end = __start_ + size();
|
|
|
|
__map_const_iterator __first_mp = __map_.begin() + __start_ / __block_size;
|
|
|
|
__map_const_iterator __last_mp = __map_.begin() + (__end - 1) / __block_size;
|
|
|
|
|
|
|
|
// Pointers to first and after last elements
|
|
|
|
// Those can be in different deque blocks
|
|
|
|
const void* __p_beg = std::__to_address(*__first_mp + (__start_ % __block_size));
|
|
|
|
const void* __p_end =
|
|
|
|
std::__to_address(*__last_mp + ((__end % __block_size == 0) ? __block_size : __end % __block_size));
|
|
|
|
|
|
|
|
for (__map_const_iterator __it = __map_.begin(); __it != __map_.end(); ++__it) {
|
|
|
|
// Go over all blocks, find the place we are in and verify its annotations
|
|
|
|
// Note that __p_end points *behind* the last item.
|
|
|
|
|
|
|
|
// - blocks before the first block with container elements
|
|
|
|
// - first block with items
|
|
|
|
// - last block with items
|
|
|
|
// - blocks after last block with ciontainer elements
|
|
|
|
|
|
|
|
// Is the block before or after deque blocks that contain elements?
|
|
|
|
if (__it < __first_mp || __it > __last_mp) {
|
|
|
|
if (!__sanitizer_verify_double_ended_contiguous_container(
|
|
|
|
std::__to_address(*__it),
|
|
|
|
std::__to_address(*__it),
|
|
|
|
std::__to_address(*__it),
|
|
|
|
std::__to_address(*__it + __block_size)))
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
const void* __containers_buffer_beg = (__it == __first_mp) ? __p_beg : (const void*)std::__to_address(*__it);
|
|
|
|
const void* __containers_buffer_end =
|
|
|
|
(__it == __last_mp) ? __p_end : (const void*)std::__to_address(*__it + __block_size);
|
|
|
|
if (!__sanitizer_verify_double_ended_contiguous_container(
|
|
|
|
std::__to_address(*__it),
|
|
|
|
__containers_buffer_beg,
|
|
|
|
__containers_buffer_end,
|
|
|
|
std::__to_address(*__it + __block_size))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
#endif // _LIBCPP_VERIFY_ASAN_DEQUE_ANNOTATIONS
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-08-01 23:11:18 +00:00
|
|
|
bool __maybe_remove_front_spare(bool __keep_one = true) {
|
|
|
|
if (__front_spare_blocks() >= 2 || (!__keep_one && __front_spare_blocks())) {
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_whole_block(0, __asan_unposion);
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::deallocate(__alloc(), __map_.front(),
|
|
|
|
__block_size);
|
|
|
|
__map_.pop_front();
|
|
|
|
__start_ -= __block_size;
|
2019-08-01 23:11:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2019-08-01 23:11:18 +00:00
|
|
|
bool __maybe_remove_back_spare(bool __keep_one = true) {
|
|
|
|
if (__back_spare_blocks() >= 2 || (!__keep_one && __back_spare_blocks())) {
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_whole_block(__map_.size() - 1, __asan_unposion);
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::deallocate(__alloc(), __map_.back(),
|
|
|
|
__block_size);
|
|
|
|
__map_.pop_back();
|
2019-08-01 23:11:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2023-05-17 07:48:24 +00:00
|
|
|
template <class _Iterator, class _Sentinel>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __assign_with_sentinel(_Iterator __f, _Sentinel __l);
|
|
|
|
|
|
|
|
template <class _RandomAccessIterator>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __assign_with_size_random_access(_RandomAccessIterator __f, difference_type __n);
|
|
|
|
template <class _Iterator>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void __assign_with_size(_Iterator __f, difference_type __n);
|
|
|
|
|
|
|
|
template <class _Iterator, class _Sentinel>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
iterator __insert_with_sentinel(const_iterator __p, _Iterator __f, _Sentinel __l);
|
|
|
|
|
|
|
|
template <class _Iterator>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
iterator __insert_with_size(const_iterator __p, _Iterator __f, size_type __n);
|
|
|
|
|
|
|
|
template <class _BiIter, class _Sentinel>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
iterator __insert_bidirectional(const_iterator __p, _BiIter __f, _Sentinel __sent, size_type __n);
|
|
|
|
template <class _BiIter>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
iterator __insert_bidirectional(const_iterator __p, _BiIter __f, _BiIter __l, size_type __n);
|
|
|
|
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _InpIter, __enable_if_t<__has_exactly_input_iterator_category<_InpIter>::value, int> = 0>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __append(_InpIter __f, _InpIter __l);
|
|
|
|
template <class _ForIter, __enable_if_t<__has_forward_iterator_category<_ForIter>::value, int> = 0>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __append(_ForIter __f, _ForIter __l);
|
2023-05-17 07:48:24 +00:00
|
|
|
|
|
|
|
template <class _InputIterator>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __append_with_size(_InputIterator __from, size_type __n);
|
|
|
|
template <class _InputIterator, class _Sentinel>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __append_with_sentinel(_InputIterator __f, _Sentinel __l);
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void __append(size_type __n);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __append(size_type __n, const value_type& __v);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __erase_to_end(const_iterator __f);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __add_front_capacity();
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __add_front_capacity(size_type __n);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __add_back_capacity();
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __add_back_capacity(size_type __n);
|
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator __move_and_check(iterator __f, iterator __l, iterator __r,
|
2010-05-11 19:42:16 +00:00
|
|
|
const_pointer& __vt);
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI iterator __move_backward_and_check(iterator __f, iterator __l, iterator __r,
|
2010-05-11 19:42:16 +00:00
|
|
|
const_pointer& __vt);
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void __move_construct_and_check(iterator __f, iterator __l,
|
2010-05-11 19:42:16 +00:00
|
|
|
iterator __r, const_pointer& __vt);
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void __move_construct_backward_and_check(iterator __f, iterator __l,
|
2010-05-11 19:42:16 +00:00
|
|
|
iterator __r, const_pointer& __vt);
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
void __copy_assign_alloc(const deque& __c)
|
|
|
|
{__copy_assign_alloc(__c, integral_constant<bool,
|
|
|
|
__alloc_traits::propagate_on_container_copy_assignment::value>());}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
void __copy_assign_alloc(const deque& __c, true_type)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__alloc() != __c.__alloc())
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
clear();
|
|
|
|
shrink_to_fit();
|
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc() = __c.__alloc();
|
|
|
|
__map_.__alloc() = __c.__map_.__alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
2011-12-01 20:21:04 +00:00
|
|
|
void __copy_assign_alloc(const deque&, false_type)
|
2010-05-11 19:42:16 +00:00
|
|
|
{}
|
|
|
|
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void __move_assign(deque& __c, true_type)
|
2011-06-02 21:38:57 +00:00
|
|
|
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value);
|
2022-08-21 00:03:35 +00:00
|
|
|
_LIBCPP_HIDE_FROM_ABI void __move_assign(deque& __c, false_type);
|
2010-05-11 19:42:16 +00:00
|
|
|
};
|
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
template <class _Tp, class _Alloc>
|
|
|
|
_LIBCPP_CONSTEXPR const typename allocator_traits<_Alloc>::difference_type deque<_Tp, _Alloc>::__block_size =
|
|
|
|
__deque_block_size<value_type, difference_type>::value;
|
|
|
|
|
2021-08-17 15:59:07 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 17
|
2018-05-18 23:44:13 +00:00
|
|
|
template<class _InputIterator,
|
2021-03-04 04:02:20 +00:00
|
|
|
class _Alloc = allocator<__iter_value_type<_InputIterator>>,
|
2023-05-17 17:34:51 +00:00
|
|
|
class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>,
|
[libc++] Use enable_if_t instead of _EnableIf
I just ran into a compiler error involving __bind_back and some overloads
that were being disabled with _EnableIf. I noticed that the error message
was quite bad and did not mention the reason for the overload being
excluded. Specifically, the error looked like this:
candidate template ignored: substitution failure [with _Args =
<ContiguousView>]: no member named '_EnableIfImpl' in 'std::_MetaBase<false>'
Instead, when using enable_if or enable_if_t, the compiler is clever and
can produce better diagnostics, like so:
candidate template ignored: requirement 'is_invocable_v<
std::__bind_back_op<1, std::integer_sequence<unsigned long, 0>>,
std::ranges::views::__transform::__fn &, std::tuple<PlusOne> &,
ContiguousView>' was not satisfied [with _Args = <ContiguousView>]
Basically, it tries to do a poor man's implementation of concepts, which
is already a lot better than simply complaining about substitution failure.
Hence, this commit uses enable_if_t instead of _EnableIf whenever
possible. That is both more straightforward than using the internal
helper, and also leads to better error messages in those cases.
I understand the motivation for _EnableIf's implementation was to improve
compile-time performance, however I believe striving to improve error
messages is even more important for our QOI, hence this patch. Furthermore,
it is unclear that _EnableIf actually improved compile-time performance
in any noticeable way (see discussion in the review for details).
Differential Revision: https://reviews.llvm.org/D108216
2021-08-17 16:26:09 +00:00
|
|
|
class = enable_if_t<__is_allocator<_Alloc>::value>
|
2018-05-18 23:44:13 +00:00
|
|
|
>
|
|
|
|
deque(_InputIterator, _InputIterator)
|
2021-03-04 04:02:20 +00:00
|
|
|
-> deque<__iter_value_type<_InputIterator>, _Alloc>;
|
2018-05-18 23:44:13 +00:00
|
|
|
|
|
|
|
template<class _InputIterator,
|
|
|
|
class _Alloc,
|
2023-05-17 17:34:51 +00:00
|
|
|
class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>,
|
[libc++] Use enable_if_t instead of _EnableIf
I just ran into a compiler error involving __bind_back and some overloads
that were being disabled with _EnableIf. I noticed that the error message
was quite bad and did not mention the reason for the overload being
excluded. Specifically, the error looked like this:
candidate template ignored: substitution failure [with _Args =
<ContiguousView>]: no member named '_EnableIfImpl' in 'std::_MetaBase<false>'
Instead, when using enable_if or enable_if_t, the compiler is clever and
can produce better diagnostics, like so:
candidate template ignored: requirement 'is_invocable_v<
std::__bind_back_op<1, std::integer_sequence<unsigned long, 0>>,
std::ranges::views::__transform::__fn &, std::tuple<PlusOne> &,
ContiguousView>' was not satisfied [with _Args = <ContiguousView>]
Basically, it tries to do a poor man's implementation of concepts, which
is already a lot better than simply complaining about substitution failure.
Hence, this commit uses enable_if_t instead of _EnableIf whenever
possible. That is both more straightforward than using the internal
helper, and also leads to better error messages in those cases.
I understand the motivation for _EnableIf's implementation was to improve
compile-time performance, however I believe striving to improve error
messages is even more important for our QOI, hence this patch. Furthermore,
it is unclear that _EnableIf actually improved compile-time performance
in any noticeable way (see discussion in the review for details).
Differential Revision: https://reviews.llvm.org/D108216
2021-08-17 16:26:09 +00:00
|
|
|
class = enable_if_t<__is_allocator<_Alloc>::value>
|
2018-05-18 23:44:13 +00:00
|
|
|
>
|
|
|
|
deque(_InputIterator, _InputIterator, _Alloc)
|
2021-03-04 04:02:20 +00:00
|
|
|
-> deque<__iter_value_type<_InputIterator>, _Alloc>;
|
2018-05-18 23:44:13 +00:00
|
|
|
#endif
|
|
|
|
|
2023-05-17 07:48:24 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 23
|
|
|
|
template <ranges::input_range _Range,
|
|
|
|
class _Alloc = allocator<ranges::range_value_t<_Range>>,
|
|
|
|
class = enable_if_t<__is_allocator<_Alloc>::value>
|
|
|
|
>
|
|
|
|
deque(from_range_t, _Range&&, _Alloc = _Alloc())
|
|
|
|
-> deque<ranges::range_value_t<_Range>, _Alloc>;
|
|
|
|
#endif
|
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
deque<_Tp, _Allocator>::deque(size_type __n)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __start_(0), __size_(0, __default_init_tag())
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__n > 0)
|
|
|
|
__append(__n);
|
|
|
|
}
|
|
|
|
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 14
|
2013-09-07 16:16:19 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
deque<_Tp, _Allocator>::deque(size_type __n, const _Allocator& __a)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
|
2013-09-07 16:16:19 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2013-09-07 16:16:19 +00:00
|
|
|
if (__n > 0)
|
|
|
|
__append(__n);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __start_(0), __size_(0, __default_init_tag())
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__n > 0)
|
|
|
|
__append(__n, __v);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> >
|
|
|
|
deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __start_(0), __size_(0, __default_init_tag())
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2010-05-11 19:42:16 +00:00
|
|
|
__append(__f, __l);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> >
|
|
|
|
deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l, const allocator_type& __a)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2010-05-11 19:42:16 +00:00
|
|
|
__append(__f, __l);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
deque<_Tp, _Allocator>::deque(const deque& __c)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __map_(__pointer_allocator(__alloc_traits::select_on_container_copy_construction(__c.__alloc()))),
|
|
|
|
__start_(0),
|
|
|
|
__size_(0, __map_.__alloc())
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2010-05-11 19:42:16 +00:00
|
|
|
__append(__c.begin(), __c.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2022-03-18 16:49:02 +00:00
|
|
|
deque<_Tp, _Allocator>::deque(const deque& __c, const __type_identity_t<allocator_type>& __a)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2010-05-11 19:42:16 +00:00
|
|
|
__append(__c.begin(), __c.end());
|
|
|
|
}
|
|
|
|
|
2017-04-16 03:17:01 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
deque<_Tp, _Allocator>&
|
|
|
|
deque<_Tp, _Allocator>::operator=(const deque& __c)
|
|
|
|
{
|
2021-09-28 17:15:18 +00:00
|
|
|
if (this != std::addressof(__c))
|
2017-04-16 03:17:01 +00:00
|
|
|
{
|
|
|
|
__copy_assign_alloc(__c);
|
|
|
|
assign(__c.begin(), __c.end());
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef _LIBCPP_CXX03_LANG
|
2011-08-12 21:56:02 +00:00
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __start_(0), __size_(0, __default_init_tag())
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2010-05-11 19:42:16 +00:00
|
|
|
__append(__il.begin(), __il.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il, const allocator_type& __a)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2010-05-11 19:42:16 +00:00
|
|
|
__append(__il.begin(), __il.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
deque<_Tp, _Allocator>::deque(deque&& __c)
|
2022-08-26 15:51:35 +00:00
|
|
|
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
|
|
|
|
: __map_(std::move(__c.__map_)), __start_(std::move(__c.__start_)), __size_(std::move(__c.__size_))
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__c.__start_ = 0;
|
|
|
|
__c.__size() = 0;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2022-03-18 16:49:02 +00:00
|
|
|
deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t<allocator_type>& __a)
|
2022-08-26 15:51:35 +00:00
|
|
|
: __map_(std::move(__c.__map_), __pointer_allocator(__a)),
|
|
|
|
__start_(std::move(__c.__start_)),
|
|
|
|
__size_(std::move(__c.__size()), __a)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__a == __c.__alloc())
|
|
|
|
{
|
|
|
|
__c.__start_ = 0;
|
|
|
|
__c.__size() = 0;
|
|
|
|
}
|
|
|
|
else
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.clear();
|
|
|
|
__start_ = 0;
|
|
|
|
__size() = 0;
|
2011-11-29 18:15:50 +00:00
|
|
|
typedef move_iterator<iterator> _Ip;
|
|
|
|
assign(_Ip(__c.begin()), _Ip(__c.end()));
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
deque<_Tp, _Allocator>&
|
|
|
|
deque<_Tp, _Allocator>::operator=(deque&& __c)
|
2011-06-02 21:38:57 +00:00
|
|
|
_NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value &&
|
|
|
|
is_nothrow_move_assignable<allocator_type>::value)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
__move_assign(__c, integral_constant<bool,
|
|
|
|
__alloc_traits::propagate_on_container_move_assignment::value>());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__move_assign(deque& __c, false_type)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__alloc() != __c.__alloc())
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2011-11-29 18:15:50 +00:00
|
|
|
typedef move_iterator<iterator> _Ip;
|
|
|
|
assign(_Ip(__c.begin()), _Ip(__c.end()));
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
__move_assign(__c, true_type());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__move_assign(deque& __c, true_type)
|
2011-06-02 21:38:57 +00:00
|
|
|
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
clear();
|
|
|
|
shrink_to_fit();
|
2022-08-26 15:51:35 +00:00
|
|
|
__move_assign(__c);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
2021-04-20 16:03:32 +00:00
|
|
|
#endif // _LIBCPP_CXX03_LANG
|
2010-05-11 19:42:16 +00:00
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value &&
|
|
|
|
!__has_random_access_iterator_category<_InputIter>::value, int> >
|
2010-05-11 19:42:16 +00:00
|
|
|
void
|
2023-08-18 20:08:04 +00:00
|
|
|
deque<_Tp, _Allocator>::assign(_InputIter __f, _InputIter __l)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2023-05-17 07:48:24 +00:00
|
|
|
__assign_with_sentinel(__f, __l);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class _Iterator, class _Sentinel>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void deque<_Tp, _Allocator>::__assign_with_sentinel(_Iterator __f, _Sentinel __l) {
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __i = begin();
|
|
|
|
iterator __e = end();
|
2014-10-27 19:28:20 +00:00
|
|
|
for (; __f != __l && __i != __e; ++__f, (void) ++__i)
|
2010-05-11 19:42:16 +00:00
|
|
|
*__i = *__f;
|
|
|
|
if (__f != __l)
|
2023-05-17 07:48:24 +00:00
|
|
|
__append_with_sentinel(std::move(__f), std::move(__l));
|
2010-05-11 19:42:16 +00:00
|
|
|
else
|
|
|
|
__erase_to_end(__i);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _RAIter, __enable_if_t<__has_random_access_iterator_category<_RAIter>::value, int> >
|
2010-05-11 19:42:16 +00:00
|
|
|
void
|
2023-08-18 20:08:04 +00:00
|
|
|
deque<_Tp, _Allocator>::assign(_RAIter __f, _RAIter __l)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2023-05-17 07:48:24 +00:00
|
|
|
__assign_with_size_random_access(__f, __l - __f);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class _RandomAccessIterator>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void deque<_Tp, _Allocator>::__assign_with_size_random_access(_RandomAccessIterator __f, difference_type __n) {
|
|
|
|
if (static_cast<size_type>(__n) > size())
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2023-05-17 07:48:24 +00:00
|
|
|
auto __l = __f + size();
|
|
|
|
std::copy(__f, __l, begin());
|
|
|
|
__append_with_size(__l, __n - size());
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
2023-05-17 07:48:24 +00:00
|
|
|
__erase_to_end(std::copy_n(__f, __n, begin()));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class _Iterator>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void deque<_Tp, _Allocator>::__assign_with_size(_Iterator __f, difference_type __n) {
|
|
|
|
if (static_cast<size_type>(__n) > size()) {
|
|
|
|
auto __added_size = __n - size();
|
|
|
|
|
|
|
|
auto __i = begin();
|
|
|
|
for (auto __count = size(); __count != 0; --__count) {
|
|
|
|
*__i++ = *__f++;
|
|
|
|
}
|
|
|
|
|
|
|
|
__append_with_size(__f, __added_size);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
__erase_to_end(std::copy_n(__f, __n, begin()));
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::assign(size_type __n, const value_type& __v)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__n > size())
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
std::fill_n(begin(), size(), __v);
|
|
|
|
__n -= size();
|
2010-05-11 19:42:16 +00:00
|
|
|
__append(__n, __v);
|
|
|
|
}
|
|
|
|
else
|
2022-08-26 15:51:35 +00:00
|
|
|
__erase_to_end(std::fill_n(begin(), __n, __v));
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
_Allocator
|
2011-06-02 16:10:22 +00:00
|
|
|
deque<_Tp, _Allocator>::get_allocator() const _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
return __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::resize(size_type __n)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__n > size())
|
|
|
|
__append(__n - size());
|
|
|
|
else if (__n < size())
|
|
|
|
__erase_to_end(begin() + __n);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::resize(size_type __n, const value_type& __v)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__n > size())
|
|
|
|
__append(__n - size(), __v);
|
|
|
|
else if (__n < size())
|
|
|
|
__erase_to_end(begin() + __n);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
2011-06-02 21:38:57 +00:00
|
|
|
deque<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (empty())
|
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_delete();
|
2022-08-26 15:51:35 +00:00
|
|
|
while (__map_.size() > 0)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::deallocate(__a, __map_.back(), __block_size);
|
|
|
|
__map_.pop_back();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
__start_ = 0;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-08-01 23:11:18 +00:00
|
|
|
__maybe_remove_front_spare(/*__keep_one=*/false);
|
|
|
|
__maybe_remove_back_spare(/*__keep_one=*/false);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.shrink_to_fit();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::reference
|
2019-03-14 21:56:57 +00:00
|
|
|
deque<_Tp, _Allocator>::operator[](size_type __i) _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __p = __start_ + __i;
|
|
|
|
return *(*(__map_.begin() + __p / __block_size) + __p % __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::const_reference
|
2019-03-14 21:56:57 +00:00
|
|
|
deque<_Tp, _Allocator>::operator[](size_type __i) const _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __p = __start_ + __i;
|
|
|
|
return *(*(__map_.begin() + __p / __block_size) + __p % __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::reference
|
|
|
|
deque<_Tp, _Allocator>::at(size_type __i)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__i >= size())
|
2021-08-19 16:15:31 +00:00
|
|
|
std::__throw_out_of_range("deque");
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __p = __start_ + __i;
|
|
|
|
return *(*(__map_.begin() + __p / __block_size) + __p % __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::const_reference
|
|
|
|
deque<_Tp, _Allocator>::at(size_type __i) const
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__i >= size())
|
2021-08-19 16:15:31 +00:00
|
|
|
std::__throw_out_of_range("deque");
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __p = __start_ + __i;
|
|
|
|
return *(*(__map_.begin() + __p / __block_size) + __p % __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::reference
|
2019-03-19 03:30:07 +00:00
|
|
|
deque<_Tp, _Allocator>::front() _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
return *(*(__map_.begin() + __start_ / __block_size)
|
|
|
|
+ __start_ % __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::const_reference
|
2019-03-19 03:30:07 +00:00
|
|
|
deque<_Tp, _Allocator>::front() const _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
return *(*(__map_.begin() + __start_ / __block_size)
|
|
|
|
+ __start_ % __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::reference
|
2019-03-19 03:30:07 +00:00
|
|
|
deque<_Tp, _Allocator>::back() _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __p = size() + __start_ - 1;
|
|
|
|
return *(*(__map_.begin() + __p / __block_size) + __p % __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::const_reference
|
2019-03-19 03:30:07 +00:00
|
|
|
deque<_Tp, _Allocator>::back() const _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __p = size() + __start_ - 1;
|
|
|
|
return *(*(__map_.begin() + __p / __block_size) + __p % __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::push_back(const value_type& __v)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__back_spare() == 0)
|
|
|
|
__add_back_capacity();
|
|
|
|
// __back_spare() >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(1);
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*end()), __v);
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
2017-04-16 03:17:01 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::push_front(const value_type& __v)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2017-04-16 03:17:01 +00:00
|
|
|
if (__front_spare() == 0)
|
|
|
|
__add_front_capacity();
|
|
|
|
// __front_spare() >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_front(1);
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--begin()), __v);
|
|
|
|
--__start_;
|
|
|
|
++__size();
|
2017-04-16 03:17:01 +00:00
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
|
2017-04-16 03:17:01 +00:00
|
|
|
#ifndef _LIBCPP_CXX03_LANG
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::push_back(value_type&& __v)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__back_spare() == 0)
|
|
|
|
__add_back_capacity();
|
|
|
|
// __back_spare() >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(1);
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*end()), std::move(__v));
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class... _Args>
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 17
|
2016-07-21 03:20:17 +00:00
|
|
|
typename deque<_Tp, _Allocator>::reference
|
2017-01-24 23:09:12 +00:00
|
|
|
#else
|
|
|
|
void
|
|
|
|
#endif
|
2010-05-11 19:42:16 +00:00
|
|
|
deque<_Tp, _Allocator>::emplace_back(_Args&&... __args)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__back_spare() == 0)
|
|
|
|
__add_back_capacity();
|
|
|
|
// __back_spare() >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(1);
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*end()),
|
2016-07-21 03:20:17 +00:00
|
|
|
std::forward<_Args>(__args)...);
|
2022-08-26 15:51:35 +00:00
|
|
|
++__size();
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 17
|
2022-08-26 15:51:35 +00:00
|
|
|
return *--end();
|
2017-01-24 23:09:12 +00:00
|
|
|
#endif
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::push_front(value_type&& __v)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__front_spare() == 0)
|
|
|
|
__add_front_capacity();
|
|
|
|
// __front_spare() >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_front(1);
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--begin()), std::move(__v));
|
|
|
|
--__start_;
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
2010-09-04 23:28:19 +00:00
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class... _Args>
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 17
|
2016-07-21 03:20:17 +00:00
|
|
|
typename deque<_Tp, _Allocator>::reference
|
2017-01-24 23:09:12 +00:00
|
|
|
#else
|
|
|
|
void
|
|
|
|
#endif
|
2010-05-11 19:42:16 +00:00
|
|
|
deque<_Tp, _Allocator>::emplace_front(_Args&&... __args)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__front_spare() == 0)
|
|
|
|
__add_front_capacity();
|
|
|
|
// __front_spare() >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_front(1);
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--begin()), std::forward<_Args>(__args)...);
|
|
|
|
--__start_;
|
|
|
|
++__size();
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 17
|
2022-08-26 15:51:35 +00:00
|
|
|
return *begin();
|
2017-01-24 23:09:12 +00:00
|
|
|
#endif
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
2017-04-16 03:17:01 +00:00
|
|
|
deque<_Tp, _Allocator>::insert(const_iterator __p, value_type&& __v)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __pos = __p - begin();
|
|
|
|
size_type __to_end = size() - __pos;
|
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos < __to_end)
|
|
|
|
{ // insert by shifting things backward
|
|
|
|
if (__front_spare() == 0)
|
|
|
|
__add_front_capacity();
|
|
|
|
// __front_spare() >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_front(1);
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos == 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--begin()), std::move(__v));
|
|
|
|
--__start_;
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __b = begin();
|
2011-06-30 21:18:19 +00:00
|
|
|
iterator __bm1 = std::prev(__b);
|
|
|
|
__alloc_traits::construct(__a, std::addressof(*__bm1), std::move(*__b));
|
2022-08-26 15:51:35 +00:00
|
|
|
--__start_;
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos > 1)
|
2017-04-16 03:17:01 +00:00
|
|
|
__b = std::move(std::next(__b), __b + __pos, __b);
|
|
|
|
*__b = std::move(__v);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // insert by shifting things forward
|
|
|
|
if (__back_spare() == 0)
|
|
|
|
__add_back_capacity();
|
|
|
|
// __back_capacity >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(1);
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __de = size() - __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__de == 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*end()), std::move(__v));
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __e = end();
|
2011-06-30 21:18:19 +00:00
|
|
|
iterator __em1 = std::prev(__e);
|
|
|
|
__alloc_traits::construct(__a, std::addressof(*__e), std::move(*__em1));
|
2022-08-26 15:51:35 +00:00
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__de > 1)
|
2017-04-16 03:17:01 +00:00
|
|
|
__e = std::move_backward(__e - __de, __em1, __e);
|
|
|
|
*--__e = std::move(__v);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
return begin() + __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2017-04-16 03:17:01 +00:00
|
|
|
template <class... _Args>
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
2017-04-16 03:17:01 +00:00
|
|
|
deque<_Tp, _Allocator>::emplace(const_iterator __p, _Args&&... __args)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __pos = __p - begin();
|
|
|
|
size_type __to_end = size() - __pos;
|
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos < __to_end)
|
|
|
|
{ // insert by shifting things backward
|
|
|
|
if (__front_spare() == 0)
|
|
|
|
__add_front_capacity();
|
|
|
|
// __front_spare() >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_front(1);
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos == 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--begin()), std::forward<_Args>(__args)...);
|
|
|
|
--__start_;
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__temp_value<value_type, _Allocator> __tmp(__alloc(), std::forward<_Args>(__args)...);
|
|
|
|
iterator __b = begin();
|
2011-06-30 21:18:19 +00:00
|
|
|
iterator __bm1 = std::prev(__b);
|
|
|
|
__alloc_traits::construct(__a, std::addressof(*__bm1), std::move(*__b));
|
2022-08-26 15:51:35 +00:00
|
|
|
--__start_;
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos > 1)
|
2011-06-30 21:18:19 +00:00
|
|
|
__b = std::move(std::next(__b), __b + __pos, __b);
|
2017-04-16 03:17:01 +00:00
|
|
|
*__b = std::move(__tmp.get());
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // insert by shifting things forward
|
|
|
|
if (__back_spare() == 0)
|
|
|
|
__add_back_capacity();
|
|
|
|
// __back_capacity >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(1);
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __de = size() - __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__de == 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*end()), std::forward<_Args>(__args)...);
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__temp_value<value_type, _Allocator> __tmp(__alloc(), std::forward<_Args>(__args)...);
|
|
|
|
iterator __e = end();
|
2011-06-30 21:18:19 +00:00
|
|
|
iterator __em1 = std::prev(__e);
|
|
|
|
__alloc_traits::construct(__a, std::addressof(*__e), std::move(*__em1));
|
2022-08-26 15:51:35 +00:00
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__de > 1)
|
2011-06-30 21:18:19 +00:00
|
|
|
__e = std::move_backward(__e - __de, __em1, __e);
|
2017-04-16 03:17:01 +00:00
|
|
|
*--__e = std::move(__tmp.get());
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
return begin() + __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
2021-04-20 16:03:32 +00:00
|
|
|
#endif // _LIBCPP_CXX03_LANG
|
2017-04-16 03:17:01 +00:00
|
|
|
|
2010-09-04 23:28:19 +00:00
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
2017-04-16 03:17:01 +00:00
|
|
|
deque<_Tp, _Allocator>::insert(const_iterator __p, const value_type& __v)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __pos = __p - begin();
|
|
|
|
size_type __to_end = size() - __pos;
|
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos < __to_end)
|
|
|
|
{ // insert by shifting things backward
|
|
|
|
if (__front_spare() == 0)
|
|
|
|
__add_front_capacity();
|
|
|
|
// __front_spare() >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_front(1);
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos == 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--begin()), __v);
|
|
|
|
--__start_;
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-04-16 03:17:01 +00:00
|
|
|
const_pointer __vt = pointer_traits<const_pointer>::pointer_to(__v);
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __b = begin();
|
2011-06-30 21:18:19 +00:00
|
|
|
iterator __bm1 = std::prev(__b);
|
2017-04-16 03:17:01 +00:00
|
|
|
if (__vt == pointer_traits<const_pointer>::pointer_to(*__b))
|
|
|
|
__vt = pointer_traits<const_pointer>::pointer_to(*__bm1);
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*__bm1), std::move(*__b));
|
2022-08-26 15:51:35 +00:00
|
|
|
--__start_;
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos > 1)
|
2017-04-16 03:17:01 +00:00
|
|
|
__b = __move_and_check(std::next(__b), __b + __pos, __b, __vt);
|
|
|
|
*__b = *__vt;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // insert by shifting things forward
|
|
|
|
if (__back_spare() == 0)
|
|
|
|
__add_back_capacity();
|
|
|
|
// __back_capacity >= 1
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(1);
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __de = size() - __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__de == 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*end()), __v);
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-04-16 03:17:01 +00:00
|
|
|
const_pointer __vt = pointer_traits<const_pointer>::pointer_to(__v);
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __e = end();
|
2011-06-30 21:18:19 +00:00
|
|
|
iterator __em1 = std::prev(__e);
|
2017-04-16 03:17:01 +00:00
|
|
|
if (__vt == pointer_traits<const_pointer>::pointer_to(*__em1))
|
|
|
|
__vt = pointer_traits<const_pointer>::pointer_to(*__e);
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*__e), std::move(*__em1));
|
2022-08-26 15:51:35 +00:00
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__de > 1)
|
2017-04-16 03:17:01 +00:00
|
|
|
__e = __move_backward_and_check(__e - __de, __em1, __e, __vt);
|
|
|
|
*--__e = *__vt;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
return begin() + __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
|
|
|
deque<_Tp, _Allocator>::insert(const_iterator __p, size_type __n, const value_type& __v)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __pos = __p - begin();
|
|
|
|
size_type __to_end = __size() - __pos;
|
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos < __to_end)
|
|
|
|
{ // insert by shifting things backward
|
|
|
|
if (__n > __front_spare())
|
|
|
|
__add_front_capacity(__n - __front_spare());
|
|
|
|
// __n <= __front_spare()
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_front(__n);
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __old_begin = begin();
|
2010-05-11 19:42:16 +00:00
|
|
|
iterator __i = __old_begin;
|
|
|
|
if (__n > __pos)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
for (size_type __m = __n - __pos; __m; --__m, --__start_, ++__size())
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--__i), __v);
|
2010-05-11 19:42:16 +00:00
|
|
|
__n = __pos;
|
|
|
|
}
|
|
|
|
if (__n > 0)
|
|
|
|
{
|
|
|
|
const_pointer __vt = pointer_traits<const_pointer>::pointer_to(__v);
|
|
|
|
iterator __obn = __old_begin + __n;
|
|
|
|
__move_construct_backward_and_check(__old_begin, __obn, __i, __vt);
|
|
|
|
if (__n < __pos)
|
|
|
|
__old_begin = __move_and_check(__obn, __old_begin + __pos, __old_begin, __vt);
|
2011-06-30 21:18:19 +00:00
|
|
|
std::fill_n(__old_begin, __n, *__vt);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // insert by shifting things forward
|
|
|
|
size_type __back_capacity = __back_spare();
|
|
|
|
if (__n > __back_capacity)
|
|
|
|
__add_back_capacity(__n - __back_capacity);
|
|
|
|
// __n <= __back_capacity
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(__n);
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __old_end = end();
|
2010-05-11 19:42:16 +00:00
|
|
|
iterator __i = __old_end;
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __de = size() - __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__n > __de)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
for (size_type __m = __n - __de; __m; --__m, (void) ++__i, ++__size())
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*__i), __v);
|
2010-05-11 19:42:16 +00:00
|
|
|
__n = __de;
|
|
|
|
}
|
|
|
|
if (__n > 0)
|
|
|
|
{
|
|
|
|
const_pointer __vt = pointer_traits<const_pointer>::pointer_to(__v);
|
|
|
|
iterator __oen = __old_end - __n;
|
|
|
|
__move_construct_and_check(__oen, __old_end, __i, __vt);
|
|
|
|
if (__n < __de)
|
|
|
|
__old_end = __move_backward_and_check(__old_end - __de, __oen, __old_end, __vt);
|
2011-06-30 21:18:19 +00:00
|
|
|
std::fill_n(__old_end - __n, __n, *__vt);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
return begin() + __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _InputIter, __enable_if_t<__has_exactly_input_iterator_category<_InputIter>::value, int> >
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
2023-08-18 20:08:04 +00:00
|
|
|
deque<_Tp, _Allocator>::insert(const_iterator __p, _InputIter __f, _InputIter __l)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2023-05-17 07:48:24 +00:00
|
|
|
return __insert_with_sentinel(__p, __f, __l);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class _Iterator, class _Sentinel>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
|
|
|
deque<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __p, _Iterator __f, _Sentinel __l) {
|
2022-08-26 15:51:35 +00:00
|
|
|
__split_buffer<value_type, allocator_type&> __buf(__alloc());
|
2023-05-17 07:48:24 +00:00
|
|
|
__buf.__construct_at_end_with_sentinel(std::move(__f), std::move(__l));
|
2010-05-11 19:42:16 +00:00
|
|
|
typedef typename __split_buffer<value_type, allocator_type&>::iterator __bi;
|
|
|
|
return insert(__p, move_iterator<__bi>(__buf.begin()), move_iterator<__bi>(__buf.end()));
|
|
|
|
}
|
|
|
|
|
2015-01-22 18:33:29 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _ForwardIterator, __enable_if_t<__has_exactly_forward_iterator_category<_ForwardIterator>::value, int> >
|
2015-01-22 18:33:29 +00:00
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
2023-08-18 20:08:04 +00:00
|
|
|
deque<_Tp, _Allocator>::insert(const_iterator __p, _ForwardIterator __f, _ForwardIterator __l)
|
2015-01-22 18:33:29 +00:00
|
|
|
{
|
2023-05-17 07:48:24 +00:00
|
|
|
return __insert_with_size(__p, __f, std::distance(__f, __l));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class _Iterator>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
|
|
|
deque<_Tp, _Allocator>::__insert_with_size(const_iterator __p, _Iterator __f, size_type __n) {
|
2022-08-26 15:51:35 +00:00
|
|
|
__split_buffer<value_type, allocator_type&> __buf(__n, 0, __alloc());
|
2023-05-17 07:48:24 +00:00
|
|
|
__buf.__construct_at_end_with_size(__f, __n);
|
2015-01-22 18:33:29 +00:00
|
|
|
typedef typename __split_buffer<value_type, allocator_type&>::iterator __fwd;
|
|
|
|
return insert(__p, move_iterator<__fwd>(__buf.begin()), move_iterator<__fwd>(__buf.end()));
|
|
|
|
}
|
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _BiIter, __enable_if_t<__has_bidirectional_iterator_category<_BiIter>::value, int> >
|
2010-05-11 19:42:16 +00:00
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
2023-08-18 20:08:04 +00:00
|
|
|
deque<_Tp, _Allocator>::insert(const_iterator __p, _BiIter __f, _BiIter __l)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2023-05-17 07:48:24 +00:00
|
|
|
return __insert_bidirectional(__p, __f, __l, std::distance(__f, __l));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class _BiIter, class _Sentinel>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
|
|
|
deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f, _Sentinel, size_type __n) {
|
|
|
|
return __insert_bidirectional(__p, __f, std::next(__f, __n), __n);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class _BiIter>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
|
|
|
deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f, _BiIter __l, size_type __n) {
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __pos = __p - begin();
|
|
|
|
size_type __to_end = size() - __pos;
|
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__pos < __to_end)
|
|
|
|
{ // insert by shifting things backward
|
|
|
|
if (__n > __front_spare())
|
|
|
|
__add_front_capacity(__n - __front_spare());
|
|
|
|
// __n <= __front_spare()
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_front(__n);
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __old_begin = begin();
|
2010-05-11 19:42:16 +00:00
|
|
|
iterator __i = __old_begin;
|
|
|
|
_BiIter __m = __f;
|
|
|
|
if (__n > __pos)
|
|
|
|
{
|
2011-06-30 21:18:19 +00:00
|
|
|
__m = __pos < __n / 2 ? std::prev(__l, __pos) : std::next(__f, __n - __pos);
|
2022-08-26 15:51:35 +00:00
|
|
|
for (_BiIter __j = __m; __j != __f; --__start_, ++__size())
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--__i), *--__j);
|
2010-05-11 19:42:16 +00:00
|
|
|
__n = __pos;
|
|
|
|
}
|
|
|
|
if (__n > 0)
|
|
|
|
{
|
|
|
|
iterator __obn = __old_begin + __n;
|
|
|
|
for (iterator __j = __obn; __j != __old_begin;)
|
|
|
|
{
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--__i), std::move(*--__j));
|
2022-08-26 15:51:35 +00:00
|
|
|
--__start_;
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
if (__n < __pos)
|
2011-06-30 21:18:19 +00:00
|
|
|
__old_begin = std::move(__obn, __old_begin + __pos, __old_begin);
|
|
|
|
std::copy(__m, __l, __old_begin);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // insert by shifting things forward
|
|
|
|
size_type __back_capacity = __back_spare();
|
|
|
|
if (__n > __back_capacity)
|
|
|
|
__add_back_capacity(__n - __back_capacity);
|
|
|
|
// __n <= __back_capacity
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(__n);
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __old_end = end();
|
2010-05-11 19:42:16 +00:00
|
|
|
iterator __i = __old_end;
|
|
|
|
_BiIter __m = __l;
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __de = size() - __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__n > __de)
|
|
|
|
{
|
2011-06-30 21:18:19 +00:00
|
|
|
__m = __de < __n / 2 ? std::next(__f, __de) : std::prev(__l, __n - __de);
|
2022-08-26 15:51:35 +00:00
|
|
|
for (_BiIter __j = __m; __j != __l; ++__i, (void) ++__j, ++__size())
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*__i), *__j);
|
2010-05-11 19:42:16 +00:00
|
|
|
__n = __de;
|
|
|
|
}
|
|
|
|
if (__n > 0)
|
|
|
|
{
|
|
|
|
iterator __oen = __old_end - __n;
|
2022-08-26 15:51:35 +00:00
|
|
|
for (iterator __j = __oen; __j != __old_end; ++__i, (void) ++__j, ++__size())
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*__i), std::move(*__j));
|
2010-05-11 19:42:16 +00:00
|
|
|
if (__n < __de)
|
2011-06-30 21:18:19 +00:00
|
|
|
__old_end = std::move_backward(__old_end - __de, __oen, __old_end);
|
|
|
|
std::copy_backward(__f, __m, __old_end);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
return begin() + __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _InpIter, __enable_if_t<__has_exactly_input_iterator_category<_InpIter>::value, int> >
|
2010-05-11 19:42:16 +00:00
|
|
|
void
|
2023-08-18 20:08:04 +00:00
|
|
|
deque<_Tp, _Allocator>::__append(_InpIter __f, _InpIter __l)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2023-05-17 07:48:24 +00:00
|
|
|
__append_with_sentinel(__f, __l);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class _InputIterator, class _Sentinel>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void deque<_Tp, _Allocator>::__append_with_sentinel(_InputIterator __f, _Sentinel __l) {
|
2010-05-11 19:42:16 +00:00
|
|
|
for (; __f != __l; ++__f)
|
2017-10-17 13:03:17 +00:00
|
|
|
#ifdef _LIBCPP_CXX03_LANG
|
2010-05-11 19:42:16 +00:00
|
|
|
push_back(*__f);
|
2017-10-17 13:03:17 +00:00
|
|
|
#else
|
|
|
|
emplace_back(*__f);
|
|
|
|
#endif
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2023-08-18 20:08:04 +00:00
|
|
|
template <class _ForIter, __enable_if_t<__has_forward_iterator_category<_ForIter>::value, int> >
|
2010-05-11 19:42:16 +00:00
|
|
|
void
|
2023-08-18 20:08:04 +00:00
|
|
|
deque<_Tp, _Allocator>::__append(_ForIter __f, _ForIter __l)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2023-05-17 07:48:24 +00:00
|
|
|
__append_with_size(__f, std::distance(__f, __l));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
template <class _InputIterator>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI
|
|
|
|
void deque<_Tp, _Allocator>::__append_with_size(_InputIterator __f, size_type __n) {
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
size_type __back_capacity = __back_spare();
|
|
|
|
if (__n > __back_capacity)
|
|
|
|
__add_back_capacity(__n - __back_capacity);
|
2023-05-17 07:48:24 +00:00
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
// __n <= __back_capacity
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(__n);
|
2022-08-26 15:51:35 +00:00
|
|
|
for (__deque_block_range __br : __deque_range(end(), end() + __n)) {
|
2019-08-12 07:51:05 +00:00
|
|
|
_ConstructTransaction __tx(this, __br);
|
|
|
|
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void)++__f) {
|
2020-11-18 23:54:38 +00:00
|
|
|
__alloc_traits::construct(__a, std::__to_address(__tx.__pos_), *__f);
|
2019-08-12 07:51:05 +00:00
|
|
|
}
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__append(size_type __n)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
size_type __back_capacity = __back_spare();
|
|
|
|
if (__n > __back_capacity)
|
|
|
|
__add_back_capacity(__n - __back_capacity);
|
|
|
|
// __n <= __back_capacity
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(__n);
|
2022-08-26 15:51:35 +00:00
|
|
|
for (__deque_block_range __br : __deque_range(end(), end() + __n)) {
|
2019-08-12 07:51:05 +00:00
|
|
|
_ConstructTransaction __tx(this, __br);
|
|
|
|
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
|
2020-11-18 23:54:38 +00:00
|
|
|
__alloc_traits::construct(__a, std::__to_address(__tx.__pos_));
|
2019-08-12 07:51:05 +00:00
|
|
|
}
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__append(size_type __n, const value_type& __v)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
size_type __back_capacity = __back_spare();
|
|
|
|
if (__n > __back_capacity)
|
|
|
|
__add_back_capacity(__n - __back_capacity);
|
|
|
|
// __n <= __back_capacity
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_increase_back(__n);
|
2022-08-26 15:51:35 +00:00
|
|
|
for (__deque_block_range __br : __deque_range(end(), end() + __n)) {
|
2019-08-12 07:51:05 +00:00
|
|
|
_ConstructTransaction __tx(this, __br);
|
|
|
|
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
|
2020-11-18 23:54:38 +00:00
|
|
|
__alloc_traits::construct(__a, std::__to_address(__tx.__pos_), __v);
|
2019-08-12 07:51:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create front capacity for one block of elements.
|
|
|
|
// Strong guarantee. Either do it or don't touch anything.
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__add_front_capacity()
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
if (__back_spare() >= __block_size)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__start_ += __block_size;
|
|
|
|
pointer __pt = __map_.back();
|
|
|
|
__map_.pop_back();
|
|
|
|
__map_.push_front(__pt);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
// Else if __map_.size() < __map_.capacity() then we need to allocate 1 buffer
|
|
|
|
else if (__map_.size() < __map_.capacity())
|
2010-05-11 19:42:16 +00:00
|
|
|
{ // we can put the new buffer into the map, but don't shift things around
|
|
|
|
// until all buffers are allocated. If we throw, we don't need to fix
|
|
|
|
// anything up (any added buffers are undetectible)
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__map_.__front_spare() > 0)
|
|
|
|
__map_.push_front(__alloc_traits::allocate(__a, __block_size));
|
2010-05-11 19:42:16 +00:00
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.push_back(__alloc_traits::allocate(__a, __block_size));
|
2010-05-11 19:42:16 +00:00
|
|
|
// Done allocating, reorder capacity
|
2022-08-26 15:51:35 +00:00
|
|
|
pointer __pt = __map_.back();
|
|
|
|
__map_.pop_back();
|
|
|
|
__map_.push_front(__pt);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
__start_ = __map_.size() == 1 ?
|
|
|
|
__block_size / 2 :
|
|
|
|
__start_ + __block_size;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
// Else need to allocate 1 buffer, *and* we need to reallocate __map_.
|
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__split_buffer<pointer, __pointer_allocator&>
|
[libc++] Add custom clang-tidy checks
Reviewed By: #libc, ldionne
Spies: jwakely, beanz, smeenai, cfe-commits, tschuett, avogelsgesang, Mordante, sstefan1, libcxx-commits, ldionne, mgorny, arichardson, miyuki
Differential Revision: https://reviews.llvm.org/D131963
2022-08-13 20:33:12 +00:00
|
|
|
__buf(std::max<size_type>(2 * __map_.capacity(), 1),
|
2022-08-26 15:51:35 +00:00
|
|
|
0, __map_.__alloc());
|
2015-03-09 17:08:51 +00:00
|
|
|
|
2015-07-13 20:04:56 +00:00
|
|
|
typedef __allocator_destructor<_Allocator> _Dp;
|
|
|
|
unique_ptr<pointer, _Dp> __hold(
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::allocate(__a, __block_size),
|
|
|
|
_Dp(__a, __block_size));
|
2015-07-13 20:04:56 +00:00
|
|
|
__buf.push_back(__hold.get());
|
|
|
|
__hold.release();
|
2018-12-12 23:58:25 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
for (__map_pointer __i = __map_.begin();
|
|
|
|
__i != __map_.end(); ++__i)
|
2010-05-11 19:42:16 +00:00
|
|
|
__buf.push_back(*__i);
|
2022-08-26 15:51:35 +00:00
|
|
|
std::swap(__map_.__first_, __buf.__first_);
|
|
|
|
std::swap(__map_.__begin_, __buf.__begin_);
|
|
|
|
std::swap(__map_.__end_, __buf.__end_);
|
|
|
|
std::swap(__map_.__end_cap(), __buf.__end_cap());
|
|
|
|
__start_ = __map_.size() == 1 ?
|
|
|
|
__block_size / 2 :
|
|
|
|
__start_ + __block_size;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_whole_block(0, __asan_poison);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create front capacity for __n elements.
|
|
|
|
// Strong guarantee. Either do it or don't touch anything.
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__add_front_capacity(size_type __n)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
size_type __nb = __recommend_blocks(__n + __map_.empty());
|
2010-05-11 19:42:16 +00:00
|
|
|
// Number of unused blocks at back:
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __back_capacity = __back_spare() / __block_size;
|
2011-06-30 21:18:19 +00:00
|
|
|
__back_capacity = std::min(__back_capacity, __nb); // don't take more than you need
|
2010-05-11 19:42:16 +00:00
|
|
|
__nb -= __back_capacity; // number of blocks need to allocate
|
|
|
|
// If __nb == 0, then we have sufficient capacity.
|
|
|
|
if (__nb == 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__start_ += __block_size * __back_capacity;
|
2010-05-11 19:42:16 +00:00
|
|
|
for (; __back_capacity > 0; --__back_capacity)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
pointer __pt = __map_.back();
|
|
|
|
__map_.pop_back();
|
|
|
|
__map_.push_front(__pt);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Else if __nb <= __map_.capacity() - __map_.size() then we need to allocate __nb buffers
|
2022-08-26 15:51:35 +00:00
|
|
|
else if (__nb <= __map_.capacity() - __map_.size())
|
2010-05-11 19:42:16 +00:00
|
|
|
{ // we can put the new buffers into the map, but don't shift things around
|
|
|
|
// until all buffers are allocated. If we throw, we don't need to fix
|
|
|
|
// anything up (any added buffers are undetectible)
|
2022-08-26 15:51:35 +00:00
|
|
|
for (; __nb > 0; --__nb, __start_ += __block_size - (__map_.size() == 1))
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__map_.__front_spare() == 0)
|
2010-05-11 19:42:16 +00:00
|
|
|
break;
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.push_front(__alloc_traits::allocate(__a, __block_size));
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_whole_block(0, __asan_poison);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
for (; __nb > 0; --__nb, ++__back_capacity)
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.push_back(__alloc_traits::allocate(__a, __block_size));
|
2010-05-11 19:42:16 +00:00
|
|
|
// Done allocating, reorder capacity
|
2022-08-26 15:51:35 +00:00
|
|
|
__start_ += __back_capacity * __block_size;
|
2010-05-11 19:42:16 +00:00
|
|
|
for (; __back_capacity > 0; --__back_capacity)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
pointer __pt = __map_.back();
|
|
|
|
__map_.pop_back();
|
|
|
|
__map_.push_front(__pt);
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_whole_block(0, __asan_poison);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Else need to allocate __nb buffers, *and* we need to reallocate __map_.
|
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __ds = (__nb + __back_capacity) * __block_size - __map_.empty();
|
|
|
|
__split_buffer<pointer, __pointer_allocator&>
|
[libc++] Add custom clang-tidy checks
Reviewed By: #libc, ldionne
Spies: jwakely, beanz, smeenai, cfe-commits, tschuett, avogelsgesang, Mordante, sstefan1, libcxx-commits, ldionne, mgorny, arichardson, miyuki
Differential Revision: https://reviews.llvm.org/D131963
2022-08-13 20:33:12 +00:00
|
|
|
__buf(std::max<size_type>(2* __map_.capacity(),
|
|
|
|
__nb + __map_.size()),
|
2022-08-26 15:51:35 +00:00
|
|
|
0, __map_.__alloc());
|
2023-02-02 10:47:01 +00:00
|
|
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
2010-05-11 19:42:16 +00:00
|
|
|
try
|
|
|
|
{
|
2023-02-02 10:47:01 +00:00
|
|
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
for (; __nb > 0; --__nb) {
|
2022-08-26 15:51:35 +00:00
|
|
|
__buf.push_back(__alloc_traits::allocate(__a, __block_size));
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
// ASan: this is empty container, we have to poison whole block
|
|
|
|
__annotate_poison_block(
|
|
|
|
std::__to_address(__buf.back()),
|
|
|
|
std::__to_address(__buf.back() + __block_size));
|
|
|
|
}
|
2023-02-02 10:47:01 +00:00
|
|
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_delete();
|
2022-08-26 15:51:35 +00:00
|
|
|
for (__map_pointer __i = __buf.begin();
|
2010-05-11 19:42:16 +00:00
|
|
|
__i != __buf.end(); ++__i)
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::deallocate(__a, *__i, __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
throw;
|
|
|
|
}
|
2023-02-02 10:47:01 +00:00
|
|
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
2010-05-11 19:42:16 +00:00
|
|
|
for (; __back_capacity > 0; --__back_capacity)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__buf.push_back(__map_.back());
|
|
|
|
__map_.pop_back();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
for (__map_pointer __i = __map_.begin();
|
|
|
|
__i != __map_.end(); ++__i)
|
2010-05-11 19:42:16 +00:00
|
|
|
__buf.push_back(*__i);
|
2022-08-26 15:51:35 +00:00
|
|
|
std::swap(__map_.__first_, __buf.__first_);
|
|
|
|
std::swap(__map_.__begin_, __buf.__begin_);
|
|
|
|
std::swap(__map_.__end_, __buf.__end_);
|
|
|
|
std::swap(__map_.__end_cap(), __buf.__end_cap());
|
|
|
|
__start_ += __ds;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create back capacity for one block of elements.
|
|
|
|
// Strong guarantee. Either do it or don't touch anything.
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__add_back_capacity()
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
if (__front_spare() >= __block_size)
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__start_ -= __block_size;
|
|
|
|
pointer __pt = __map_.front();
|
|
|
|
__map_.pop_front();
|
|
|
|
__map_.push_back(__pt);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
// Else if __nb <= __map_.capacity() - __map_.size() then we need to allocate __nb buffers
|
2022-08-26 15:51:35 +00:00
|
|
|
else if (__map_.size() < __map_.capacity())
|
2010-05-11 19:42:16 +00:00
|
|
|
{ // we can put the new buffer into the map, but don't shift things around
|
|
|
|
// until it is allocated. If we throw, we don't need to fix
|
|
|
|
// anything up (any added buffers are undetectible)
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__map_.__back_spare() != 0)
|
|
|
|
__map_.push_back(__alloc_traits::allocate(__a, __block_size));
|
2010-05-11 19:42:16 +00:00
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.push_front(__alloc_traits::allocate(__a, __block_size));
|
2010-05-11 19:42:16 +00:00
|
|
|
// Done allocating, reorder capacity
|
2022-08-26 15:51:35 +00:00
|
|
|
pointer __pt = __map_.front();
|
|
|
|
__map_.pop_front();
|
|
|
|
__map_.push_back(__pt);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_whole_block(__map_.size() - 1, __asan_poison);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
// Else need to allocate 1 buffer, *and* we need to reallocate __map_.
|
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__split_buffer<pointer, __pointer_allocator&>
|
[libc++] Add custom clang-tidy checks
Reviewed By: #libc, ldionne
Spies: jwakely, beanz, smeenai, cfe-commits, tschuett, avogelsgesang, Mordante, sstefan1, libcxx-commits, ldionne, mgorny, arichardson, miyuki
Differential Revision: https://reviews.llvm.org/D131963
2022-08-13 20:33:12 +00:00
|
|
|
__buf(std::max<size_type>(2* __map_.capacity(), 1),
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.size(),
|
|
|
|
__map_.__alloc());
|
2015-03-09 17:08:51 +00:00
|
|
|
|
2015-07-13 20:04:56 +00:00
|
|
|
typedef __allocator_destructor<_Allocator> _Dp;
|
|
|
|
unique_ptr<pointer, _Dp> __hold(
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::allocate(__a, __block_size),
|
|
|
|
_Dp(__a, __block_size));
|
2015-07-13 20:04:56 +00:00
|
|
|
__buf.push_back(__hold.get());
|
|
|
|
__hold.release();
|
2015-03-09 17:08:51 +00:00
|
|
|
|
2022-08-26 15:51:35 +00:00
|
|
|
for (__map_pointer __i = __map_.end();
|
|
|
|
__i != __map_.begin();)
|
2010-05-11 19:42:16 +00:00
|
|
|
__buf.push_front(*--__i);
|
2022-08-26 15:51:35 +00:00
|
|
|
std::swap(__map_.__first_, __buf.__first_);
|
|
|
|
std::swap(__map_.__begin_, __buf.__begin_);
|
|
|
|
std::swap(__map_.__end_, __buf.__end_);
|
|
|
|
std::swap(__map_.__end_cap(), __buf.__end_cap());
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_whole_block(__map_.size() - 1, __asan_poison);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create back capacity for __n elements.
|
|
|
|
// Strong guarantee. Either do it or don't touch anything.
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__add_back_capacity(size_type __n)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
size_type __nb = __recommend_blocks(__n + __map_.empty());
|
2010-05-11 19:42:16 +00:00
|
|
|
// Number of unused blocks at front:
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __front_capacity = __front_spare() / __block_size;
|
2011-06-30 21:18:19 +00:00
|
|
|
__front_capacity = std::min(__front_capacity, __nb); // don't take more than you need
|
2010-05-11 19:42:16 +00:00
|
|
|
__nb -= __front_capacity; // number of blocks need to allocate
|
|
|
|
// If __nb == 0, then we have sufficient capacity.
|
|
|
|
if (__nb == 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__start_ -= __block_size * __front_capacity;
|
2010-05-11 19:42:16 +00:00
|
|
|
for (; __front_capacity > 0; --__front_capacity)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
pointer __pt = __map_.front();
|
|
|
|
__map_.pop_front();
|
|
|
|
__map_.push_back(__pt);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Else if __nb <= __map_.capacity() - __map_.size() then we need to allocate __nb buffers
|
2022-08-26 15:51:35 +00:00
|
|
|
else if (__nb <= __map_.capacity() - __map_.size())
|
2010-05-11 19:42:16 +00:00
|
|
|
{ // we can put the new buffers into the map, but don't shift things around
|
|
|
|
// until all buffers are allocated. If we throw, we don't need to fix
|
|
|
|
// anything up (any added buffers are undetectible)
|
|
|
|
for (; __nb > 0; --__nb)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
if (__map_.__back_spare() == 0)
|
2010-05-11 19:42:16 +00:00
|
|
|
break;
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.push_back(__alloc_traits::allocate(__a, __block_size));
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_whole_block(__map_.size() - 1, __asan_poison);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
for (; __nb > 0; --__nb, ++__front_capacity, __start_ +=
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__block_size - (__map_.size() == 1)) {
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.push_front(__alloc_traits::allocate(__a, __block_size));
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_whole_block(0, __asan_poison);
|
|
|
|
}
|
2010-05-11 19:42:16 +00:00
|
|
|
// Done allocating, reorder capacity
|
2022-08-26 15:51:35 +00:00
|
|
|
__start_ -= __block_size * __front_capacity;
|
2010-05-11 19:42:16 +00:00
|
|
|
for (; __front_capacity > 0; --__front_capacity)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
pointer __pt = __map_.front();
|
|
|
|
__map_.pop_front();
|
|
|
|
__map_.push_back(__pt);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Else need to allocate __nb buffers, *and* we need to reallocate __map_.
|
|
|
|
else
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
size_type __ds = __front_capacity * __block_size;
|
|
|
|
__split_buffer<pointer, __pointer_allocator&>
|
[libc++] Add custom clang-tidy checks
Reviewed By: #libc, ldionne
Spies: jwakely, beanz, smeenai, cfe-commits, tschuett, avogelsgesang, Mordante, sstefan1, libcxx-commits, ldionne, mgorny, arichardson, miyuki
Differential Revision: https://reviews.llvm.org/D131963
2022-08-13 20:33:12 +00:00
|
|
|
__buf(std::max<size_type>(2* __map_.capacity(),
|
|
|
|
__nb + __map_.size()),
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.size() - __front_capacity,
|
|
|
|
__map_.__alloc());
|
2023-02-02 10:47:01 +00:00
|
|
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
2010-05-11 19:42:16 +00:00
|
|
|
try
|
|
|
|
{
|
2023-02-02 10:47:01 +00:00
|
|
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
for (; __nb > 0; --__nb) {
|
2022-08-26 15:51:35 +00:00
|
|
|
__buf.push_back(__alloc_traits::allocate(__a, __block_size));
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
// ASan: this is an empty container, we have to poison the whole block
|
|
|
|
__annotate_poison_block(
|
|
|
|
std::__to_address(__buf.back()),
|
|
|
|
std::__to_address(__buf.back() + __block_size));
|
|
|
|
}
|
2023-02-02 10:47:01 +00:00
|
|
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_delete();
|
2022-08-26 15:51:35 +00:00
|
|
|
for (__map_pointer __i = __buf.begin();
|
2010-05-11 19:42:16 +00:00
|
|
|
__i != __buf.end(); ++__i)
|
2022-08-26 15:51:35 +00:00
|
|
|
__alloc_traits::deallocate(__a, *__i, __block_size);
|
2010-05-11 19:42:16 +00:00
|
|
|
throw;
|
|
|
|
}
|
2023-02-02 10:47:01 +00:00
|
|
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
2010-05-11 19:42:16 +00:00
|
|
|
for (; __front_capacity > 0; --__front_capacity)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__buf.push_back(__map_.front());
|
|
|
|
__map_.pop_front();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
for (__map_pointer __i = __map_.end();
|
|
|
|
__i != __map_.begin();)
|
2010-05-11 19:42:16 +00:00
|
|
|
__buf.push_front(*--__i);
|
2022-08-26 15:51:35 +00:00
|
|
|
std::swap(__map_.__first_, __buf.__first_);
|
|
|
|
std::swap(__map_.__begin_, __buf.__begin_);
|
|
|
|
std::swap(__map_.__end_, __buf.__end_);
|
|
|
|
std::swap(__map_.__end_cap(), __buf.__end_cap());
|
|
|
|
__start_ -= __ds;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::pop_front()
|
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
size_type __old_sz = size();
|
|
|
|
size_type __old_start = __start_;
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
__alloc_traits::destroy(__a, std::__to_address(*(__map_.begin() +
|
|
|
|
__start_ / __block_size) +
|
|
|
|
__start_ % __block_size));
|
|
|
|
--__size();
|
|
|
|
++__start_;
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_shrink_front(__old_sz, __old_start);
|
2019-08-01 23:11:18 +00:00
|
|
|
__maybe_remove_front_spare();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::pop_back()
|
|
|
|
{
|
2023-07-20 17:13:54 +00:00
|
|
|
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "deque::pop_back called on an empty deque");
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
size_type __old_sz = size();
|
|
|
|
size_type __old_start = __start_;
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
size_type __p = size() + __start_ - 1;
|
|
|
|
__alloc_traits::destroy(__a, std::__to_address(*(__map_.begin() +
|
|
|
|
__p / __block_size) +
|
|
|
|
__p % __block_size));
|
|
|
|
--__size();
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_shrink_back(__old_sz, __old_start);
|
2019-08-01 23:11:18 +00:00
|
|
|
__maybe_remove_back_spare();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// move assign [__f, __l) to [__r, __r + (__l-__f)).
|
|
|
|
// If __vt points into [__f, __l), then subtract (__f - __r) from __vt.
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
|
|
|
deque<_Tp, _Allocator>::__move_and_check(iterator __f, iterator __l, iterator __r,
|
|
|
|
const_pointer& __vt)
|
|
|
|
{
|
|
|
|
// as if
|
|
|
|
// for (; __f != __l; ++__f, ++__r)
|
2011-06-30 21:18:19 +00:00
|
|
|
// *__r = std::move(*__f);
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __n = __l - __f;
|
|
|
|
while (__n > 0)
|
|
|
|
{
|
|
|
|
pointer __fb = __f.__ptr_;
|
2022-08-26 15:51:35 +00:00
|
|
|
pointer __fe = *__f.__m_iter_ + __block_size;
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __bs = __fe - __fb;
|
|
|
|
if (__bs > __n)
|
|
|
|
{
|
|
|
|
__bs = __n;
|
|
|
|
__fe = __fb + __bs;
|
|
|
|
}
|
|
|
|
if (__fb <= __vt && __vt < __fe)
|
2013-06-23 21:17:24 +00:00
|
|
|
__vt = (const_iterator(static_cast<__map_const_pointer>(__f.__m_iter_), __vt) -= __f - __r).__ptr_;
|
2011-06-30 21:18:19 +00:00
|
|
|
__r = std::move(__fb, __fe, __r);
|
2010-05-11 19:42:16 +00:00
|
|
|
__n -= __bs;
|
|
|
|
__f += __bs;
|
|
|
|
}
|
|
|
|
return __r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// move assign [__f, __l) to [__r - (__l-__f), __r) backwards.
|
|
|
|
// If __vt points into [__f, __l), then add (__r - __l) to __vt.
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
|
|
|
deque<_Tp, _Allocator>::__move_backward_and_check(iterator __f, iterator __l, iterator __r,
|
|
|
|
const_pointer& __vt)
|
|
|
|
{
|
|
|
|
// as if
|
|
|
|
// while (__f != __l)
|
2011-06-30 21:18:19 +00:00
|
|
|
// *--__r = std::move(*--__l);
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __n = __l - __f;
|
|
|
|
while (__n > 0)
|
|
|
|
{
|
|
|
|
--__l;
|
|
|
|
pointer __lb = *__l.__m_iter_;
|
|
|
|
pointer __le = __l.__ptr_ + 1;
|
|
|
|
difference_type __bs = __le - __lb;
|
|
|
|
if (__bs > __n)
|
|
|
|
{
|
|
|
|
__bs = __n;
|
|
|
|
__lb = __le - __bs;
|
|
|
|
}
|
|
|
|
if (__lb <= __vt && __vt < __le)
|
2013-06-23 21:17:24 +00:00
|
|
|
__vt = (const_iterator(static_cast<__map_const_pointer>(__l.__m_iter_), __vt) += __r - __l - 1).__ptr_;
|
2011-06-30 21:18:19 +00:00
|
|
|
__r = std::move_backward(__lb, __le, __r);
|
2010-05-11 19:42:16 +00:00
|
|
|
__n -= __bs;
|
|
|
|
__l -= __bs - 1;
|
|
|
|
}
|
|
|
|
return __r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// move construct [__f, __l) to [__r, __r + (__l-__f)).
|
|
|
|
// If __vt points into [__f, __l), then add (__r - __f) to __vt.
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__move_construct_and_check(iterator __f, iterator __l,
|
|
|
|
iterator __r, const_pointer& __vt)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
// as if
|
2022-08-26 15:51:35 +00:00
|
|
|
// for (; __f != __l; ++__r, ++__f, ++__size())
|
2011-06-30 21:18:19 +00:00
|
|
|
// __alloc_traits::construct(__a, std::addressof(*__r), std::move(*__f));
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __n = __l - __f;
|
|
|
|
while (__n > 0)
|
|
|
|
{
|
|
|
|
pointer __fb = __f.__ptr_;
|
2022-08-26 15:51:35 +00:00
|
|
|
pointer __fe = *__f.__m_iter_ + __block_size;
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __bs = __fe - __fb;
|
|
|
|
if (__bs > __n)
|
|
|
|
{
|
|
|
|
__bs = __n;
|
|
|
|
__fe = __fb + __bs;
|
|
|
|
}
|
|
|
|
if (__fb <= __vt && __vt < __fe)
|
2013-06-23 21:17:24 +00:00
|
|
|
__vt = (const_iterator(static_cast<__map_const_pointer>(__f.__m_iter_), __vt) += __r - __f).__ptr_;
|
2022-08-26 15:51:35 +00:00
|
|
|
for (; __fb != __fe; ++__fb, ++__r, ++__size())
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*__r), std::move(*__fb));
|
2010-05-11 19:42:16 +00:00
|
|
|
__n -= __bs;
|
|
|
|
__f += __bs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// move construct [__f, __l) to [__r - (__l-__f), __r) backwards.
|
|
|
|
// If __vt points into [__f, __l), then subtract (__l - __r) from __vt.
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__move_construct_backward_and_check(iterator __f, iterator __l,
|
|
|
|
iterator __r, const_pointer& __vt)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
2010-05-11 19:42:16 +00:00
|
|
|
// as if
|
|
|
|
// for (iterator __j = __l; __j != __f;)
|
|
|
|
// {
|
2011-06-30 21:18:19 +00:00
|
|
|
// __alloc_traitsconstruct(__a, std::addressof(*--__r), std::move(*--__j));
|
2022-08-26 15:51:35 +00:00
|
|
|
// --__start_;
|
|
|
|
// ++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
// }
|
|
|
|
difference_type __n = __l - __f;
|
|
|
|
while (__n > 0)
|
|
|
|
{
|
|
|
|
--__l;
|
|
|
|
pointer __lb = *__l.__m_iter_;
|
|
|
|
pointer __le = __l.__ptr_ + 1;
|
|
|
|
difference_type __bs = __le - __lb;
|
|
|
|
if (__bs > __n)
|
|
|
|
{
|
|
|
|
__bs = __n;
|
|
|
|
__lb = __le - __bs;
|
|
|
|
}
|
|
|
|
if (__lb <= __vt && __vt < __le)
|
2013-06-23 21:17:24 +00:00
|
|
|
__vt = (const_iterator(static_cast<__map_const_pointer>(__l.__m_iter_), __vt) -= __l - __r + 1).__ptr_;
|
2010-05-11 19:42:16 +00:00
|
|
|
while (__le != __lb)
|
|
|
|
{
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::construct(__a, std::addressof(*--__r), std::move(*--__le));
|
2022-08-26 15:51:35 +00:00
|
|
|
--__start_;
|
|
|
|
++__size();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
__n -= __bs;
|
|
|
|
__l -= __bs - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
|
|
|
deque<_Tp, _Allocator>::erase(const_iterator __f)
|
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
size_type __old_sz = size();
|
|
|
|
size_type __old_start = __start_;
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __b = begin();
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __pos = __f - __b;
|
|
|
|
iterator __p = __b + __pos;
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
if (static_cast<size_t>(__pos) <= (size() - 1) / 2)
|
2010-05-11 19:42:16 +00:00
|
|
|
{ // erase from front
|
2011-06-30 21:18:19 +00:00
|
|
|
std::move_backward(__b, __p, std::next(__p));
|
|
|
|
__alloc_traits::destroy(__a, std::addressof(*__b));
|
2022-08-26 15:51:35 +00:00
|
|
|
--__size();
|
|
|
|
++__start_;
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_shrink_front(__old_sz, __old_start);
|
2019-08-01 23:11:18 +00:00
|
|
|
__maybe_remove_front_spare();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // erase from back
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __i = std::move(std::next(__p), end(), __p);
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::destroy(__a, std::addressof(*__i));
|
2022-08-26 15:51:35 +00:00
|
|
|
--__size();
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_shrink_back(__old_sz, __old_start);
|
2019-08-01 23:11:18 +00:00
|
|
|
__maybe_remove_back_spare();
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
return begin() + __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
typename deque<_Tp, _Allocator>::iterator
|
|
|
|
deque<_Tp, _Allocator>::erase(const_iterator __f, const_iterator __l)
|
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
size_type __old_sz = size();
|
|
|
|
size_type __old_start = __start_;
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __n = __l - __f;
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __b = begin();
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __pos = __f - __b;
|
|
|
|
iterator __p = __b + __pos;
|
|
|
|
if (__n > 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
if (static_cast<size_t>(__pos) <= (size() - __n) / 2)
|
2010-05-11 19:42:16 +00:00
|
|
|
{ // erase from front
|
2011-06-30 21:18:19 +00:00
|
|
|
iterator __i = std::move_backward(__b, __p, __p + __n);
|
2010-05-11 19:42:16 +00:00
|
|
|
for (; __b != __i; ++__b)
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::destroy(__a, std::addressof(*__b));
|
2022-08-26 15:51:35 +00:00
|
|
|
__size() -= __n;
|
|
|
|
__start_ += __n;
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_shrink_front(__old_sz, __old_start);
|
2019-08-01 23:11:18 +00:00
|
|
|
while (__maybe_remove_front_spare()) {
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // erase from back
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __i = std::move(__p + __n, end(), __p);
|
|
|
|
for (iterator __e = end(); __i != __e; ++__i)
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::destroy(__a, std::addressof(*__i));
|
2022-08-26 15:51:35 +00:00
|
|
|
__size() -= __n;
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_shrink_back(__old_sz, __old_start);
|
2019-08-01 23:11:18 +00:00
|
|
|
while (__maybe_remove_back_spare()) {
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-26 15:51:35 +00:00
|
|
|
return begin() + __pos;
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::__erase_to_end(const_iterator __f)
|
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
size_type __old_sz = size();
|
|
|
|
size_type __old_start = __start_;
|
2022-08-26 15:51:35 +00:00
|
|
|
iterator __e = end();
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __n = __e - __f;
|
|
|
|
if (__n > 0)
|
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
iterator __b = begin();
|
2010-05-11 19:42:16 +00:00
|
|
|
difference_type __pos = __f - __b;
|
|
|
|
for (iterator __p = __b + __pos; __p != __e; ++__p)
|
2011-06-30 21:18:19 +00:00
|
|
|
__alloc_traits::destroy(__a, std::addressof(*__p));
|
2022-08-26 15:51:35 +00:00
|
|
|
__size() -= __n;
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_shrink_back(__old_sz, __old_start);
|
2019-08-01 23:11:18 +00:00
|
|
|
while (__maybe_remove_back_spare()) {
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
void
|
|
|
|
deque<_Tp, _Allocator>::swap(deque& __c)
|
2015-07-13 20:04:56 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 14
|
|
|
|
_NOEXCEPT
|
|
|
|
#else
|
2018-12-12 23:58:25 +00:00
|
|
|
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
|
2015-07-13 20:04:56 +00:00
|
|
|
__is_nothrow_swappable<allocator_type>::value)
|
|
|
|
#endif
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
2022-08-26 15:51:35 +00:00
|
|
|
__map_.swap(__c.__map_);
|
|
|
|
std::swap(__start_, __c.__start_);
|
|
|
|
std::swap(__size(), __c.__size());
|
|
|
|
std::__swap_allocator(__alloc(), __c.__alloc());
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2015-11-07 01:22:13 +00:00
|
|
|
inline
|
2010-05-11 19:42:16 +00:00
|
|
|
void
|
2011-06-02 16:10:22 +00:00
|
|
|
deque<_Tp, _Allocator>::clear() _NOEXCEPT
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_delete();
|
2022-08-26 15:51:35 +00:00
|
|
|
allocator_type& __a = __alloc();
|
|
|
|
for (iterator __i = begin(), __e = end(); __i != __e; ++__i)
|
|
|
|
__alloc_traits::destroy(__a, std::addressof(*__i));
|
|
|
|
__size() = 0;
|
|
|
|
while (__map_.size() > 2)
|
|
|
|
{
|
|
|
|
__alloc_traits::deallocate(__a, __map_.front(), __block_size);
|
|
|
|
__map_.pop_front();
|
|
|
|
}
|
|
|
|
switch (__map_.size())
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
__start_ = __block_size / 2;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
__start_ = __block_size;
|
|
|
|
break;
|
|
|
|
}
|
[2a/3][ASan][libcxx] std::deque annotations
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector`, to `std::string` and `std::deque` collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for `std::deque`, or between the size and capacity bounds for `std::string`).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took `iter1_begin`, `iter1_end`, `iter2_begin` iterators (with a custom comparison function). When object `iter1` was longer than `iter2`, read out-of-bounds on `iter2` could happen. Container sanitization would detect it.
This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.
This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.
Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to `libcxx/test/support/asan_testing.h`. This function can be used to verify whether a `std::deque` object has been correctly annotated.
Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.
If you have any questions, please email:
- advenam.tacet@trailofbits.com
- disconnect3d@trailofbits.com
Reviewed By: #libc, philnik
Differential Revision: https://reviews.llvm.org/D132092
2023-06-01 05:13:24 +00:00
|
|
|
__annotate_new(0);
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2022-08-21 00:03:35 +00:00
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
bool
|
|
|
|
operator==(const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y)
|
|
|
|
{
|
|
|
|
const typename deque<_Tp, _Allocator>::size_type __sz = __x.size();
|
2011-06-30 21:18:19 +00:00
|
|
|
return __sz == __y.size() && std::equal(__x.begin(), __x.end(), __y.begin());
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
2023-03-03 12:35:07 +00:00
|
|
|
#if _LIBCPP_STD_VER <= 17
|
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
2022-08-21 00:03:35 +00:00
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
bool
|
|
|
|
operator!=(const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y)
|
|
|
|
{
|
|
|
|
return !(__x == __y);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2022-08-21 00:03:35 +00:00
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
bool
|
|
|
|
operator< (const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y)
|
|
|
|
{
|
2011-06-30 21:18:19 +00:00
|
|
|
return std::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end());
|
2010-05-11 19:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2022-08-21 00:03:35 +00:00
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
bool
|
|
|
|
operator> (const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y)
|
|
|
|
{
|
|
|
|
return __y < __x;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2022-08-21 00:03:35 +00:00
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
bool
|
|
|
|
operator>=(const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y)
|
|
|
|
{
|
|
|
|
return !(__x < __y);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp, class _Allocator>
|
2022-08-21 00:03:35 +00:00
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
bool
|
|
|
|
operator<=(const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y)
|
|
|
|
{
|
|
|
|
return !(__y < __x);
|
|
|
|
}
|
|
|
|
|
2023-03-03 12:35:07 +00:00
|
|
|
#else // _LIBCPP_STD_VER <= 17
|
|
|
|
|
2023-05-23 20:03:35 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
|
|
|
_LIBCPP_HIDE_FROM_ABI __synth_three_way_result<_Tp>
|
|
|
|
operator<=>(const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y) {
|
2023-03-03 12:35:07 +00:00
|
|
|
return std::lexicographical_compare_three_way(
|
2023-03-21 17:05:35 +00:00
|
|
|
__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way<_Tp, _Tp>);
|
2023-03-03 12:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // _LIBCPP_STD_VER <= 17
|
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
template <class _Tp, class _Allocator>
|
2022-08-21 00:03:35 +00:00
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
2010-05-11 19:42:16 +00:00
|
|
|
void
|
|
|
|
swap(deque<_Tp, _Allocator>& __x, deque<_Tp, _Allocator>& __y)
|
2011-06-02 20:00:14 +00:00
|
|
|
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
|
2010-05-11 19:42:16 +00:00
|
|
|
{
|
|
|
|
__x.swap(__y);
|
|
|
|
}
|
|
|
|
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 20
|
2018-12-14 18:49:35 +00:00
|
|
|
template <class _Tp, class _Allocator, class _Up>
|
2022-08-21 00:03:35 +00:00
|
|
|
inline _LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::size_type
|
2020-05-02 11:58:03 +00:00
|
|
|
erase(deque<_Tp, _Allocator>& __c, const _Up& __v) {
|
|
|
|
auto __old_size = __c.size();
|
|
|
|
__c.erase(std::remove(__c.begin(), __c.end(), __v), __c.end());
|
|
|
|
return __old_size - __c.size();
|
|
|
|
}
|
2018-12-14 18:49:35 +00:00
|
|
|
|
|
|
|
template <class _Tp, class _Allocator, class _Predicate>
|
2022-08-21 00:03:35 +00:00
|
|
|
inline _LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::size_type
|
2020-05-02 11:58:03 +00:00
|
|
|
erase_if(deque<_Tp, _Allocator>& __c, _Predicate __pred) {
|
|
|
|
auto __old_size = __c.size();
|
|
|
|
__c.erase(std::remove_if(__c.begin(), __c.end(), __pred), __c.end());
|
|
|
|
return __old_size - __c.size();
|
|
|
|
}
|
2021-09-26 13:47:42 +00:00
|
|
|
|
|
|
|
template <>
|
|
|
|
inline constexpr bool __format::__enable_insertable<std::deque<char>> = true;
|
|
|
|
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
|
|
|
template <>
|
|
|
|
inline constexpr bool __format::__enable_insertable<std::deque<wchar_t>> = true;
|
2018-12-14 18:49:35 +00:00
|
|
|
#endif
|
|
|
|
|
2023-02-13 23:56:09 +00:00
|
|
|
#endif // _LIBCPP_STD_VER >= 20
|
2018-12-14 18:49:35 +00:00
|
|
|
|
2010-05-11 19:42:16 +00:00
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
|
2023-02-13 23:56:09 +00:00
|
|
|
#if _LIBCPP_STD_VER >= 17
|
2022-10-06 20:53:30 +00:00
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
namespace pmr {
|
|
|
|
template <class _ValueT>
|
2023-03-29 20:48:20 +00:00
|
|
|
using deque _LIBCPP_AVAILABILITY_PMR = std::deque<_ValueT, polymorphic_allocator<_ValueT>>;
|
2022-10-06 20:53:30 +00:00
|
|
|
} // namespace pmr
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
#endif
|
|
|
|
|
2017-05-31 22:07:49 +00:00
|
|
|
_LIBCPP_POP_MACROS
|
|
|
|
|
2022-09-02 15:53:28 +00:00
|
|
|
#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
|
|
|
|
# include <algorithm>
|
2022-09-22 19:53:13 +00:00
|
|
|
# include <atomic>
|
2022-11-02 19:27:42 +00:00
|
|
|
# include <concepts>
|
2023-01-08 15:47:53 +00:00
|
|
|
# include <cstdlib>
|
2022-09-02 15:53:28 +00:00
|
|
|
# include <functional>
|
2022-09-22 19:53:13 +00:00
|
|
|
# include <iosfwd>
|
2022-09-02 15:53:28 +00:00
|
|
|
# include <iterator>
|
2023-02-12 11:32:36 +00:00
|
|
|
# include <type_traits>
|
2022-09-22 19:53:13 +00:00
|
|
|
# include <typeinfo>
|
2022-09-02 15:53:28 +00:00
|
|
|
#endif
|
|
|
|
|
2021-04-20 16:03:32 +00:00
|
|
|
#endif // _LIBCPP_DEQUE
|