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