Home | History | Annotate | Download | only in synchronization
      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()
     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 
     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 
     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 
     78 LockImpl::~LockImpl() {
     79   int rv = pthread_mutex_destroy(&native_handle_);
     80   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
     81 }
     82 
     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 
     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
    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