tor-browser

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

ref_counted.cc (3234B)


      1 // Copyright 2011 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 #include "base/memory/ref_counted.h"
      6 
      7 #include <limits>
      8 #include <ostream>
      9 #include <type_traits>
     10 
     11 #include "base/threading/thread_collision_warner.h"
     12 
     13 namespace base {
     14 namespace {
     15 
     16 #if DCHECK_IS_ON()
     17 std::atomic_int g_cross_thread_ref_count_access_allow_count(0);
     18 #endif
     19 
     20 }  // namespace
     21 
     22 namespace subtle {
     23 
     24 bool RefCountedThreadSafeBase::HasOneRef() const {
     25  return ref_count_.IsOne();
     26 }
     27 
     28 bool RefCountedThreadSafeBase::HasAtLeastOneRef() const {
     29  return !ref_count_.IsZero();
     30 }
     31 
     32 #if DCHECK_IS_ON()
     33 RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
     34  DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
     35                      "calling Release()";
     36 }
     37 #endif
     38 
     39 // For security and correctness, we check the arithmetic on ref counts.
     40 //
     41 // In an attempt to avoid binary bloat (from inlining the `CHECK`), we define
     42 // these functions out-of-line. However, compilers are wily. Further testing may
     43 // show that `NOINLINE` helps or hurts.
     44 //
     45 #if defined(ARCH_CPU_64_BITS)
     46 void RefCountedBase::AddRefImpl() const {
     47  // An attacker could induce use-after-free bugs, and potentially exploit them,
     48  // by creating so many references to a ref-counted object that the reference
     49  // count overflows. On 32-bit architectures, there is not enough address space
     50  // to succeed. But on 64-bit architectures, it might indeed be possible.
     51  // Therefore, we can elide the check for arithmetic overflow on 32-bit, but we
     52  // must check on 64-bit.
     53  //
     54  // Make sure the addition didn't wrap back around to 0. This form of check
     55  // works because we assert that `ref_count_` is an unsigned integer type.
     56  CHECK(++ref_count_ != 0);
     57 }
     58 
     59 void RefCountedBase::ReleaseImpl() const {
     60  // Make sure the subtraction didn't wrap back around from 0 to the max value.
     61  // That could cause memory leaks, and may induce application-semantic
     62  // correctness or safety bugs. (E.g. what if we really needed that object to
     63  // be destroyed at the right time?)
     64  //
     65  // Note that unlike with overflow, underflow could also happen on 32-bit
     66  // architectures. Arguably, we should do this check on32-bit machines too.
     67  CHECK(--ref_count_ != std::numeric_limits<decltype(ref_count_)>::max());
     68 }
     69 #endif
     70 
     71 #if !(defined(ARCH_CPU_X86_FAMILY) || defined(__ARM_FEATURE_ATOMICS))
     72 bool RefCountedThreadSafeBase::Release() const {
     73  return ReleaseImpl();
     74 }
     75 void RefCountedThreadSafeBase::AddRef() const {
     76  AddRefImpl();
     77 }
     78 void RefCountedThreadSafeBase::AddRefWithCheck() const {
     79  AddRefWithCheckImpl();
     80 }
     81 #endif
     82 
     83 #if DCHECK_IS_ON()
     84 bool RefCountedBase::CalledOnValidSequence() const {
     85 #if defined(MOZ_SANDBOX)
     86  return true;
     87 #else
     88  return sequence_checker_.CalledOnValidSequence() ||
     89         g_cross_thread_ref_count_access_allow_count.load() != 0;
     90 #endif
     91 }
     92 #endif
     93 
     94 }  // namespace subtle
     95 
     96 #if DCHECK_IS_ON()
     97 ScopedAllowCrossThreadRefCountAccess::ScopedAllowCrossThreadRefCountAccess() {
     98  ++g_cross_thread_ref_count_access_allow_count;
     99 }
    100 
    101 ScopedAllowCrossThreadRefCountAccess::~ScopedAllowCrossThreadRefCountAccess() {
    102  --g_cross_thread_ref_count_access_allow_count;
    103 }
    104 #endif
    105 
    106 }  // namespace base