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