tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

observer_list_internal.h (5916B)


      1 // Copyright 2018 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_OBSERVER_LIST_INTERNAL_H_
      6 #define BASE_OBSERVER_LIST_INTERNAL_H_
      7 
      8 #include <string>
      9 
     10 #include "base/base_export.h"
     11 #include "base/check.h"
     12 #include "base/containers/linked_list.h"
     13 #include "base/dcheck_is_on.h"
     14 #include "base/memory/raw_ptr.h"
     15 #include "base/memory/raw_ptr_exclusion.h"
     16 #include "base/memory/weak_ptr.h"
     17 #include "base/observer_list_types.h"
     18 
     19 #if DCHECK_IS_ON()
     20 #include "base/debug/stack_trace.h"
     21 #endif
     22 
     23 namespace base {
     24 namespace internal {
     25 
     26 // Adapter for putting raw pointers into an ObserverList<Foo>::Unchecked.
     27 class BASE_EXPORT UncheckedObserverAdapter {
     28 public:
     29  explicit UncheckedObserverAdapter(const void* observer)
     30      : ptr_(const_cast<void*>(observer)) {}
     31  UncheckedObserverAdapter(const UncheckedObserverAdapter&) = delete;
     32  UncheckedObserverAdapter& operator=(const UncheckedObserverAdapter&) = delete;
     33  UncheckedObserverAdapter(UncheckedObserverAdapter&& other) = default;
     34  UncheckedObserverAdapter& operator=(UncheckedObserverAdapter&& other) =
     35      default;
     36 
     37  void MarkForRemoval() { ptr_ = nullptr; }
     38 
     39  bool IsMarkedForRemoval() const { return !ptr_; }
     40  bool IsEqual(const void* rhs) const { return ptr_ == rhs; }
     41 
     42  template <class ObserverType>
     43  static ObserverType* Get(const UncheckedObserverAdapter& adapter) {
     44    static_assert(
     45        !std::is_base_of_v<CheckedObserver, ObserverType>,
     46        "CheckedObserver classes must not use ObserverList<T>::Unchecked.");
     47    return static_cast<ObserverType*>(adapter.ptr_);
     48  }
     49 
     50 #if DCHECK_IS_ON()
     51  std::string GetCreationStackString() const {
     52    return "Observer created at:\n" + stack_.ToString();
     53  }
     54 #endif  // DCHECK_IS_ON()
     55 
     56 private:
     57  raw_ptr<void, AcrossTasksDanglingUntriaged> ptr_;
     58 #if DCHECK_IS_ON()
     59  base::debug::StackTrace stack_;
     60 #endif  // DCHECK_IS_ON()
     61 };
     62 
     63 // Adapter for CheckedObserver types so that they can use the same syntax as a
     64 // raw pointer when stored in the std::vector of observers in an ObserverList.
     65 // It wraps a WeakPtr<CheckedObserver> and allows a "null" pointer via
     66 // destruction to be distinguished from an observer marked for deferred removal
     67 // whilst an iteration is in progress.
     68 class BASE_EXPORT CheckedObserverAdapter {
     69 public:
     70  explicit CheckedObserverAdapter(const CheckedObserver* observer);
     71 
     72  // Move-only construction and assignment is required to store this in STL
     73  // types.
     74  CheckedObserverAdapter(CheckedObserverAdapter&& other);
     75  CheckedObserverAdapter& operator=(CheckedObserverAdapter&& other);
     76  CheckedObserverAdapter(const CheckedObserverAdapter&) = delete;
     77  CheckedObserverAdapter& operator=(const CheckedObserverAdapter&) = delete;
     78  ~CheckedObserverAdapter();
     79 
     80  void MarkForRemoval() {
     81    DCHECK(weak_ptr_);
     82    weak_ptr_ = nullptr;
     83  }
     84 
     85  bool IsMarkedForRemoval() const {
     86    // If |weak_ptr_| was invalidated then this attempt to iterate over the
     87    // pointer is a UAF. Tip: If it's unclear where the `delete` occurred, try
     88    // adding CHECK(!IsInObserverList()) to the ~CheckedObserver() (destructor)
     89    // override. However, note that this is not always a bug: a destroyed
     90    // observer can exist in an ObserverList so long as nothing iterates over
     91    // the ObserverList before the list itself is destroyed.
     92    CHECK(!weak_ptr_.WasInvalidated());
     93    return weak_ptr_ == nullptr;
     94  }
     95 
     96  bool IsEqual(const CheckedObserver* rhs) const {
     97    // Note that inside an iteration, ObserverList::HasObserver() may call this
     98    // and |weak_ptr_| may be null due to a deferred removal, which is fine.
     99    return weak_ptr_.get() == rhs;
    100  }
    101 
    102  template <class ObserverType>
    103  static ObserverType* Get(const CheckedObserverAdapter& adapter) {
    104    static_assert(
    105        std::is_base_of_v<CheckedObserver, ObserverType>,
    106        "Observers should inherit from base::CheckedObserver. "
    107        "Use ObserverList<T>::Unchecked to observe with raw pointers.");
    108    DCHECK(adapter.weak_ptr_);
    109    return static_cast<ObserverType*>(adapter.weak_ptr_.get());
    110  }
    111 
    112 #if DCHECK_IS_ON()
    113  std::string GetCreationStackString() const { return stack_.ToString(); }
    114 #endif
    115 
    116 private:
    117  WeakPtr<CheckedObserver> weak_ptr_;
    118 #if DCHECK_IS_ON()
    119  base::debug::StackTrace stack_;
    120 #endif
    121 };
    122 
    123 // Wraps a pointer in a stack-allocated, base::LinkNode. The node is
    124 // automatically removed from the linked list upon destruction (of the node, not
    125 // the pointer). Nodes are detached from the list via Invalidate() in the
    126 // destructor of ObserverList. This invalidates all WeakLinkNodes. There is no
    127 // threading support.
    128 template <class ObserverList>
    129 class WeakLinkNode : public base::LinkNode<WeakLinkNode<ObserverList>> {
    130 public:
    131  WeakLinkNode() = default;
    132  explicit WeakLinkNode(ObserverList* list) { SetList(list); }
    133  WeakLinkNode(const WeakLinkNode&) = delete;
    134  WeakLinkNode& operator=(const WeakLinkNode&) = delete;
    135 
    136  ~WeakLinkNode() { Invalidate(); }
    137 
    138  bool IsOnlyRemainingNode() const {
    139    return list_ &&
    140           list_->live_iterators_.head() == list_->live_iterators_.tail();
    141  }
    142 
    143  void SetList(ObserverList* list) {
    144    DCHECK(!list_);
    145    DCHECK(list);
    146    list_ = list;
    147    list_->live_iterators_.Append(this);
    148  }
    149 
    150  void Invalidate() {
    151    if (list_) {
    152      list_ = nullptr;
    153      this->RemoveFromList();
    154    }
    155  }
    156 
    157  ObserverList* get() const {
    158    if (list_)
    159      DCHECK_CALLED_ON_VALID_SEQUENCE(list_->iteration_sequence_checker_);
    160    return list_;
    161  }
    162  ObserverList* operator->() const { return get(); }
    163  explicit operator bool() const { return get(); }
    164 
    165 private:
    166  // `list_` is not a raw_ptr<...> for performance reasons: on-stack pointer +
    167  // based on analysis of sampling profiler data and tab_search:top100:2020.
    168  RAW_PTR_EXCLUSION ObserverList* list_ = nullptr;
    169 };
    170 
    171 }  // namespace internal
    172 }  // namespace base
    173 
    174 #endif  // BASE_OBSERVER_LIST_INTERNAL_H_