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