• 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 "base/synchronization/lock_impl.h"
6 
7 #include <string>
8 
9 #include "base/debug/activity_tracker.h"
10 #include "base/logging.h"
11 #include "base/posix/safe_strerror.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/synchronization/lock.h"
14 #include "base/synchronization/synchronization_buildflags.h"
15 #include "build/build_config.h"
16 
17 namespace base {
18 namespace internal {
19 
20 namespace {
21 
22 #if DCHECK_IS_ON()
AdditionalHintForSystemErrorCode(int error_code)23 const char* AdditionalHintForSystemErrorCode(int error_code) {
24   switch (error_code) {
25     case EINVAL:
26       return "Hint: This is often related to a use-after-free.";
27     default:
28       return "";
29   }
30 }
31 #endif  // DCHECK_IS_ON()
32 
SystemErrorCodeToString(int error_code)33 std::string SystemErrorCodeToString(int error_code) {
34 #if DCHECK_IS_ON()
35   return base::safe_strerror(error_code) + ". " +
36          AdditionalHintForSystemErrorCode(error_code);
37 #else   // DCHECK_IS_ON()
38   return std::string();
39 #endif  // DCHECK_IS_ON()
40 }
41 
42 }  // namespace
43 
44 // Determines which platforms can consider using priority inheritance locks. Use
45 // this define for platform code that may not compile if priority inheritance
46 // locks aren't available. For this platform code,
47 // PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check.
48 // Lock::PriorityInheritanceAvailable still must be checked as the code may
49 // compile but the underlying platform still may not correctly support priority
50 // inheritance locks.
51 #if defined(OS_NACL) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
52 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0
53 #else
54 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1
55 #endif
56 
LockImpl()57 LockImpl::LockImpl() {
58   pthread_mutexattr_t mta;
59   int rv = pthread_mutexattr_init(&mta);
60   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
61 #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE()
62   if (PriorityInheritanceAvailable()) {
63     rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT);
64     DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
65   }
66 #endif
67 #ifndef NDEBUG
68   // In debug, setup attributes for lock error checking.
69   rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
70   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
71 #endif
72   rv = pthread_mutex_init(&native_handle_, &mta);
73   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
74   rv = pthread_mutexattr_destroy(&mta);
75   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
76 }
77 
~LockImpl()78 LockImpl::~LockImpl() {
79   int rv = pthread_mutex_destroy(&native_handle_);
80   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
81 }
82 
Try()83 bool LockImpl::Try() {
84   int rv = pthread_mutex_trylock(&native_handle_);
85   DCHECK(rv == 0 || rv == EBUSY) << ". " << SystemErrorCodeToString(rv);
86   return rv == 0;
87 }
88 
Lock()89 void LockImpl::Lock() {
90   // The ScopedLockAcquireActivity below is relatively expensive and so its
91   // actions can become significant due to the very large number of locks
92   // that tend to be used throughout the build. To avoid this cost in the
93   // vast majority of the calls, simply "try" the lock first and only do the
94   // (tracked) blocking call if that fails. Since "try" itself is a system
95   // call, and thus also somewhat expensive, don't bother with it unless
96   // tracking is actually enabled.
97   if (base::debug::GlobalActivityTracker::IsEnabled())
98     if (Try())
99       return;
100 
101   base::debug::ScopedLockAcquireActivity lock_activity(this);
102   int rv = pthread_mutex_lock(&native_handle_);
103   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
104 }
105 
106 // static
PriorityInheritanceAvailable()107 bool LockImpl::PriorityInheritanceAvailable() {
108 #if BUILDFLAG(ENABLE_MUTEX_PRIORITY_INHERITANCE)
109   return true;
110 #elif PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(OS_MACOSX)
111   return true;
112 #else
113   // Security concerns prevent the use of priority inheritance mutexes on Linux.
114   //   * CVE-2010-0622 - Linux < 2.6.33-rc7, wake_futex_pi possible DoS.
115   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622
116   //   * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS.
117   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647
118   //   * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation.
119   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153
120   //
121   // If the above were all addressed, we still need a runtime check to deal with
122   // the bug below.
123   //   * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652
124   //     Fixed in glibc 2.17.
125   //     Priority inheritance mutexes may deadlock with condition variables
126   //     during reacquisition of the mutex after the condition variable is
127   //     signalled.
128   return false;
129 #endif
130 }
131 
132 }  // namespace internal
133 }  // namespace base
134