brintos

brintos / llvm-project-archived public Read only

0
0
Text · 36.8 KiB · d0f96f5 Raw
1124 lines · plain
1 2======================3Thread Safety Analysis4======================5 6Introduction7============8 9Clang Thread Safety Analysis is a C++ language extension which warns about10potential race conditions in code.  The analysis is completely static (i.e.11compile-time); there is no run-time overhead.  The analysis is still12under active development, but it is mature enough to be deployed in an13industrial setting.  It is being developed by Google, in collaboration with14CERT/SEI, and is used extensively in Google's internal code base.15 16Thread safety analysis works very much like a type system for multi-threaded17programs.  In addition to declaring the *type* of data (e.g. ``int``, ``float``,18etc.), the programmer can (optionally) declare how access to that data is19controlled in a multi-threaded environment.  For example, if ``foo`` is20*guarded by* the mutex ``mu``, then the analysis will issue a warning whenever21a piece of code reads or writes to ``foo`` without first locking ``mu``.22Similarly, if there are particular routines that should only be called by23the GUI thread, then the analysis will warn if other threads call those24routines.25 26Getting Started27----------------28 29.. code-block:: c++30 31  #include "mutex.h"32 33  class BankAccount {34  private:35    Mutex mu;36    int   balance GUARDED_BY(mu);37 38    void depositImpl(int amount) {39      balance += amount;       // WARNING! Cannot write balance without locking mu.40    }41 42    void withdrawImpl(int amount) REQUIRES(mu) {43      balance -= amount;       // OK. Caller must have locked mu.44    }45 46  public:47    void withdraw(int amount) {48      mu.Lock();49      withdrawImpl(amount);    // OK.  We've locked mu.50    }                          // WARNING!  Failed to unlock mu.51 52    void transferFrom(BankAccount& b, int amount) {53      mu.Lock();54      b.withdrawImpl(amount);  // WARNING!  Calling withdrawImpl() requires locking b.mu.55      depositImpl(amount);     // OK.  depositImpl() has no requirements.56      mu.Unlock();57    }58  };59 60This example demonstrates the basic concepts behind the analysis.  The61``GUARDED_BY`` attribute declares that a thread must lock ``mu`` before it can62read or write to ``balance``, thus ensuring that the increment and decrement63operations are atomic.  Similarly, ``REQUIRES`` declares that64the calling thread must lock ``mu`` before calling ``withdrawImpl``.65Because the caller is assumed to have locked ``mu``, it is safe to modify66``balance`` within the body of the method.67 68The ``depositImpl()`` method does not have ``REQUIRES``, so the69analysis issues a warning.  Thread safety analysis is not inter-procedural, so70caller requirements must be explicitly declared.71There is also a warning in ``transferFrom()``, because although the method72locks ``this->mu``, it does not lock ``b.mu``.  The analysis understands73that these are two separate mutexes, in two different objects.74 75Finally, there is a warning in the ``withdraw()`` method, because it fails to76unlock ``mu``.  Every lock must have a corresponding unlock, and the analysis77will detect both double locks, and double unlocks.  A function is allowed to78acquire a lock without releasing it, (or vice versa), but it must be annotated79as such (using ``ACQUIRE``/``RELEASE``).80 81 82Running The Analysis83--------------------84 85To run the analysis, simply compile with the ``-Wthread-safety`` flag, e.g.86 87.. code-block:: bash88 89  clang -c -Wthread-safety example.cpp90 91Note that this example assumes the presence of a suitably annotated92:ref:`mutexheader` that declares which methods perform locking,93unlocking, and so on.94 95 96Basic Concepts: Capabilities97============================98 99Thread safety analysis provides a way of protecting *resources* with100*capabilities*.  A resource is either a data member, or a function/method101that provides access to some underlying resource.  The analysis ensures that102the calling thread cannot access the *resource* (i.e. call the function, or103read/write the data) unless it has the *capability* to do so.104 105Capabilities are associated with named C++ objects which declare specific106methods to acquire and release the capability.  The name of the object serves107to identify the capability.  The most common example is a mutex.  For example,108if ``mu`` is a mutex, then calling ``mu.Lock()`` causes the calling thread109to acquire the capability to access data that is protected by ``mu``. Similarly,110calling ``mu.Unlock()`` releases that capability.111 112A thread may hold a capability either *exclusively* or *shared*.  An exclusive113capability can be held by only one thread at a time, while a shared capability114can be held by many threads at the same time.  This mechanism enforces a115multiple-reader, single-writer pattern.  Write operations to protected data116require exclusive access, while read operations require only shared access.117 118At any given moment during program execution, a thread holds a specific set of119capabilities (e.g. the set of mutexes that it has locked.)  These act like keys120or tokens that allow the thread to access a given resource.  Just like physical121security keys, a thread cannot make a copy of a capability, nor can it destroy122one.  A thread can only release a capability to another thread, or acquire one123from another thread.  The annotations are deliberately agnostic about the124exact mechanism used to acquire and release capabilities; it assumes that the125underlying implementation (e.g. the Mutex implementation) does the handoff in126an appropriate manner.127 128The set of capabilities that are actually held by a given thread at a given129point in program execution is a run-time concept.  The static analysis works130by calculating an approximation of that set, called the *capability131environment*.  The capability environment is calculated for every program point,132and describes the set of capabilities that are statically known to be held, or133not held, at that particular point.  This environment is a conservative134approximation of the full set of capabilities that will actually be held by a135thread at run-time.136 137 138Reference Guide139===============140 141The thread safety analysis uses attributes to declare threading constraints.142Attributes must be attached to named declarations, such as classes, methods,143and data members. Users are *strongly advised* to define macros for the various144attributes; example definitions can be found in :ref:`mutexheader`, below.145The following documentation assumes the use of macros.146 147The attributes only control assumptions made by thread safety analysis and the148warnings it issues.  They don't affect generated code or behavior at run-time.149 150For historical reasons, prior versions of thread safety used macro names that151were very lock-centric.  These macros have since been renamed to fit a more152general capability model.  The prior names are still in use, and will be153mentioned under the tag *previously* where appropriate.154 155 156GUARDED_BY(c) and PT_GUARDED_BY(c)157----------------------------------158 159``GUARDED_BY`` is an attribute on data members, which declares that the data160member is protected by the given capability.  Read operations on the data161require shared access, while write operations require exclusive access.162 163``PT_GUARDED_BY`` is similar, but is intended for use on pointers and smart164pointers. There is no constraint on the data member itself, but the *data that165it points to* is protected by the given capability.166 167.. code-block:: c++168 169  Mutex mu;170  int *p1             GUARDED_BY(mu);171  int *p2             PT_GUARDED_BY(mu);172  unique_ptr<int> p3  PT_GUARDED_BY(mu);173 174  void test() {175    p1 = 0;             // Warning!176 177    *p2 = 42;           // Warning!178    p2 = new int;       // OK.179 180    *p3 = 42;           // Warning!181    p3.reset(new int);  // OK.182  }183 184 185REQUIRES(...), REQUIRES_SHARED(...)186-----------------------------------187 188*Previously*: ``EXCLUSIVE_LOCKS_REQUIRED``, ``SHARED_LOCKS_REQUIRED``189 190``REQUIRES`` is an attribute on functions, methods or function parameters of191reference to :ref:`scoped_capability`-annotated type, which192declares that the calling thread must have exclusive access to the given193capabilities.  More than one capability may be specified.  The capabilities194must be held on entry to the function, *and must still be held on exit*.195Additionally, if the attribute is on a function parameter, it declares that196the scoped capability manages the specified capabilities in the given order.197 198``REQUIRES_SHARED`` is similar, but requires only shared access.199 200.. code-block:: c++201 202  Mutex mu1, mu2;203  int a GUARDED_BY(mu1);204  int b GUARDED_BY(mu2);205 206  void foo() REQUIRES(mu1, mu2) {207    a = 0;208    b = 0;209  }210 211  void test() {212    mu1.Lock();213    foo();         // Warning!  Requires mu2.214    mu1.Unlock();215  }216 217  void require(MutexLocker& scope REQUIRES(mu1)) {218    scope.Unlock();219    a = 0; // Warning!  Requires mu1.220    scope.Lock();221  }222 223  void testParameter() {224    MutexLocker scope(&mu1), scope2(&mu2);225    require(scope2); // Warning! Mutex managed by 'scope2' is 'mu2' instead of 'mu1'226    require(scope); // OK.227    scope.Unlock();228    require(scope); // Warning!  Requires mu1.229  }230 231 232ACQUIRE(...), ACQUIRE_SHARED(...), RELEASE(...), RELEASE_SHARED(...), RELEASE_GENERIC(...)233------------------------------------------------------------------------------------------234 235*Previously*: ``EXCLUSIVE_LOCK_FUNCTION``, ``SHARED_LOCK_FUNCTION``,236``UNLOCK_FUNCTION``237 238``ACQUIRE`` and ``ACQUIRE_SHARED`` are attributes on functions, methods239or function parameters of reference to :ref:`scoped_capability`-annotated type,240which declare that the function acquires a capability, but does not release it.241The given capability must not be held on entry, and will be held on exit242(exclusively for ``ACQUIRE``, shared for ``ACQUIRE_SHARED``).243Additionally, if the attribute is on a function parameter, it declares that244the scoped capability manages the specified capabilities in the given order.245 246``RELEASE``, ``RELEASE_SHARED``, and ``RELEASE_GENERIC`` declare that the247function releases the given capability.  The capability must be held on entry248(exclusively for ``RELEASE``, shared for ``RELEASE_SHARED``, exclusively or249shared for ``RELEASE_GENERIC``), and will no longer be held on exit.250 251.. code-block:: c++252 253  Mutex mu;254  MyClass myObject GUARDED_BY(mu);255 256  void lockAndInit() ACQUIRE(mu) {257    mu.Lock();258    myObject.init();259  }260 261  void cleanupAndUnlock() RELEASE(mu) {262    myObject.cleanup();263  }                          // Warning!  Need to unlock mu.264 265  void test() {266    lockAndInit();267    myObject.doSomething();268    cleanupAndUnlock();269    myObject.doSomething();  // Warning, mu is not locked.270  }271 272  void release(MutexLocker& scope RELEASE(mu)) {273  }                          // Warning!  Need to unlock mu.274 275  void testParameter() {276    MutexLocker scope(&mu);277    release(scope);278  }279 280If no argument is passed to ``ACQUIRE`` or ``RELEASE``, then the argument is281assumed to be ``this``, and the analysis will not check the body of the282function.  This pattern is intended for use by classes which hide locking283details behind an abstract interface.  For example:284 285.. code-block:: c++286 287  template <class T>288  class CAPABILITY("mutex") Container {289  private:290    Mutex mu;291    T* data;292 293  public:294    // Hide mu from public interface.295    void Lock()   ACQUIRE() { mu.Lock(); }296    void Unlock() RELEASE() { mu.Unlock(); }297 298    T& getElem(int i) { return data[i]; }299  };300 301  void test() {302    Container<int> c;303    c.Lock();304    int i = c.getElem(0);305    c.Unlock();306  }307 308 309EXCLUDES(...)310-------------311 312*Previously*: ``LOCKS_EXCLUDED``313 314``EXCLUDES`` is an attribute on functions, methods or function parameters315of reference to :ref:`scoped_capability`-annotated type, which declares that316the caller must *not* hold the given capabilities.  This annotation is317used to prevent deadlock.  Many mutex implementations are not re-entrant, so318deadlock can occur if the function acquires the mutex a second time.319Additionally, if the attribute is on a function parameter, it declares that320the scoped capability manages the specified capabilities in the given order.321 322.. code-block:: c++323 324  Mutex mu;325  int a GUARDED_BY(mu);326 327  void clear() EXCLUDES(mu) {328    mu.Lock();329    a = 0;330    mu.Unlock();331  }332 333  void reset() {334    mu.Lock();335    clear();     // Warning!  Caller cannot hold 'mu'.336    mu.Unlock();337  }338 339  void exclude(MutexLocker& scope LOCKS_EXCLUDED(mu)) {340    scope.Unlock(); // Warning! mu is not locked.341    scope.Lock();342  } // Warning! mu still held at the end of function.343 344  void testParameter() {345    MutexLocker scope(&mu);346    exclude(scope); // Warning, mu is held.347  }348 349Unlike ``REQUIRES``, ``EXCLUDES`` is optional.  The analysis will not issue a350warning if the attribute is missing, which can lead to false negatives in some351cases.  This issue is discussed further in :ref:`negative`.352 353 354NO_THREAD_SAFETY_ANALYSIS355-------------------------356 357``NO_THREAD_SAFETY_ANALYSIS`` is an attribute on functions or methods, which358turns off thread safety checking for that method.  It provides an escape hatch359for functions which are either (1) deliberately thread-unsafe, or (2) are360thread-safe, but too complicated for the analysis to understand.  Reasons for361(2) will be described in the :ref:`limitations`, below.362 363.. code-block:: c++364 365  class Counter {366    Mutex mu;367    int a GUARDED_BY(mu);368 369    void unsafeIncrement() NO_THREAD_SAFETY_ANALYSIS { a++; }370  };371 372Unlike the other attributes, ``NO_THREAD_SAFETY_ANALYSIS`` is not part of the373interface of a function, and should thus be placed on the function definition374(in the ``.cc`` or ``.cpp`` file) rather than on the function declaration375(in the header).376 377 378RETURN_CAPABILITY(c)379--------------------380 381*Previously*: ``LOCK_RETURNED``382 383``RETURN_CAPABILITY`` is an attribute on functions or methods, which declares384that the function returns a reference to the given capability.  It is used to385annotate getter methods that return mutexes.386 387.. code-block:: c++388 389  class MyClass {390  private:391    Mutex mu;392    int a GUARDED_BY(mu);393 394  public:395    Mutex* getMu() RETURN_CAPABILITY(mu) { return &mu; }396 397    // analysis knows that getMu() == mu398    void clear() REQUIRES(getMu()) { a = 0; }399  };400 401 402ACQUIRED_BEFORE(...), ACQUIRED_AFTER(...)403-----------------------------------------404 405``ACQUIRED_BEFORE`` and ``ACQUIRED_AFTER`` are attributes on member406declarations, specifically declarations of mutexes or other capabilities.407These declarations enforce a particular order in which the mutexes must be408acquired, in order to prevent deadlock.409 410.. code-block:: c++411 412  Mutex m1;413  Mutex m2 ACQUIRED_AFTER(m1);414 415  // Alternative declaration416  // Mutex m2;417  // Mutex m1 ACQUIRED_BEFORE(m2);418 419  void foo() {420    m2.Lock();421    m1.Lock();  // Warning!  m2 must be acquired after m1.422    m1.Unlock();423    m2.Unlock();424  }425 426 427CAPABILITY(<string>)428--------------------429 430*Previously*: ``LOCKABLE``431 432``CAPABILITY`` is an attribute on classes, which specifies that objects of the433class can be used as a capability.  The string argument specifies the kind of434capability in error messages, e.g. ``"mutex"``.  See the ``Container`` example435given above, or the ``Mutex`` class in :ref:`mutexheader`.436 437REENTRANT_CAPABILITY438--------------------439 440``REENTRANT_CAPABILITY`` is an attribute on capability classes, denoting that441they are reentrant. Marking a capability as reentrant means that acquiring the442same capability multiple times is safe. Acquiring the same capability with443different access privileges (exclusive vs. shared) again is not considered444reentrant by the analysis.445 446Note: In many cases this attribute is only required where a capability is447acquired reentrant within the same function, such as via macros or other448helpers. Otherwise, best practice is to avoid explicitly acquiring a capability449multiple times within the same function, and letting the analysis produce450warnings on double-acquisition attempts.451 452.. _scoped_capability:453 454SCOPED_CAPABILITY455-----------------456 457*Previously*: ``SCOPED_LOCKABLE``458 459``SCOPED_CAPABILITY`` is an attribute on classes that implement RAII-style460locking, in which a capability is acquired in the constructor, and released in461the destructor.  Such classes require special handling because the constructor462and destructor refer to the capability via different names; see the463``MutexLocker`` class in :ref:`mutexheader`, below.464 465Scoped capabilities are treated as capabilities that are implicitly acquired466on construction and released on destruction. They are associated with467the set of (regular) capabilities named in thread safety attributes on the468constructor or function returning them by value (using C++17 guaranteed copy469elision). Acquire-type attributes on other member functions are treated as470applying to that set of associated capabilities, while ``RELEASE`` implies that471a function releases all associated capabilities in whatever mode they're held.472 473 474TRY_ACQUIRE(<bool>, ...), TRY_ACQUIRE_SHARED(<bool>, ...)475---------------------------------------------------------476 477*Previously:* ``EXCLUSIVE_TRYLOCK_FUNCTION``, ``SHARED_TRYLOCK_FUNCTION``478 479These are attributes on a function or method that tries to acquire the given480capability, and returns a boolean value indicating success or failure.481The first argument must be ``true`` or ``false``, to specify which return value482indicates success, and the remaining arguments are interpreted in the same way483as ``ACQUIRE``.  See :ref:`mutexheader`, below, for example uses.484 485Because the analysis doesn't support conditional locking, a capability is486treated as acquired after the first branch on the return value of a try-acquire487function.488 489.. code-block:: c++490 491  Mutex mu;492  int a GUARDED_BY(mu);493 494  void foo() {495    bool success = mu.TryLock();496    a = 0;         // Warning, mu is not locked.497    if (success) {498      a = 0;       // Ok.499      mu.Unlock();500    } else {501      a = 0;       // Warning, mu is not locked.502    }503  }504 505 506ASSERT_CAPABILITY(...) and ASSERT_SHARED_CAPABILITY(...)507--------------------------------------------------------508 509*Previously:*  ``ASSERT_EXCLUSIVE_LOCK``, ``ASSERT_SHARED_LOCK``510 511These are attributes on a function or method which asserts the calling thread512already holds the given capability, for example, by performing a run-time test513and terminating if the capability is not held.  Presence of this annotation514causes the analysis to assume the capability is held after calls to the515annotated function.  See :ref:`mutexheader`, below, for example uses.516 517 518GUARDED_VAR and PT_GUARDED_VAR519------------------------------520 521Use of these attributes has been deprecated.522 523 524Warning flags525-------------526 527* ``-Wthread-safety``:  Umbrella flag which turns on the following:528 529  + ``-Wthread-safety-attributes``: Semantic checks for thread safety attributes.530  + ``-Wthread-safety-analysis``: The core analysis.531  + ``-Wthread-safety-precise``: Requires that mutex expressions match precisely.532       This warning can be disabled for code which has a lot of aliases.533  + ``-Wthread-safety-reference``: Checks when guarded members are passed or534    returned by reference.535 536* ``-Wthread-safety-pointer``: Checks when passing or returning pointers to537  guarded variables, or pointers to guarded data, as function argument or538  return value respectively.539 540:ref:`negative` are an experimental feature, which are enabled with:541 542* ``-Wthread-safety-negative``:  Negative capabilities.  Off by default.543 544When new features and checks are added to the analysis, they can often introduce545additional warnings.  Those warnings are initially released as *beta* warnings546for a period of time, after which they are migrated into the standard analysis.547 548* ``-Wthread-safety-beta``:  New features.  Off by default.549 550 551.. _negative:552 553Negative Capabilities554=====================555 556Thread Safety Analysis is designed to prevent both race conditions and557deadlock.  The ``GUARDED_BY`` and ``REQUIRES`` attributes prevent race conditions, by558ensuring that a capability is held before reading or writing to guarded data,559and the ``EXCLUDES`` attribute prevents deadlock, by making sure that a mutex is560*not* held.561 562However, ``EXCLUDES`` is an optional attribute, and does not provide the same563safety guarantee as ``REQUIRES``.  In particular:564 565  * A function which acquires a capability does not have to exclude it.566  * A function which calls a function that excludes a capability does not567    have to transitively exclude that capability.568 569As a result, ``EXCLUDES`` can easily produce false negatives:570 571.. code-block:: c++572 573  class Foo {574    Mutex mu;575 576    void foo() {577      mu.Lock();578      bar();           // No warning.579      baz();           // No warning.580      mu.Unlock();581    }582 583    void bar() {       // No warning.  (Should have EXCLUDES(mu)).584      mu.Lock();585      // ...586      mu.Unlock();587    }588 589    void baz() {590      bif();           // No warning.  (Should have EXCLUDES(mu)).591    }592 593    void bif() EXCLUDES(mu);594  };595 596 597Negative requirements are an alternative to ``EXCLUDES`` that provide598a stronger safety guarantee.  A negative requirement uses the  ``REQUIRES``599attribute, in conjunction with the ``!`` operator, to indicate that a capability600should *not* be held.601 602For example, using ``REQUIRES(!mu)`` instead of ``EXCLUDES(mu)`` will produce603the appropriate warnings:604 605.. code-block:: c++606 607  class FooNeg {608    Mutex mu;609 610    void foo() REQUIRES(!mu) {   // foo() now requires !mu.611      mu.Lock();612      bar();613      baz();614      mu.Unlock();615    }616 617    void bar() {618      mu.Lock();       // WARNING!  Missing REQUIRES(!mu).619      // ...620      mu.Unlock();621    }622 623    void baz() {624      bif();           // WARNING!  Missing REQUIRES(!mu).625    }626 627    void bif() REQUIRES(!mu);628  };629 630 631Negative requirements are an experimental feature which is off by default,632because it will produce many warnings in existing code.  It can be enabled633by passing ``-Wthread-safety-negative``.634 635 636.. _faq:637 638Frequently Asked Questions639==========================640 641(Q) Should I put attributes in the header file, or in the .cc/.cpp/.cxx file?642 643(A) Attributes are part of the formal interface of a function, and should644always go in the header, where they are visible to anything that includes645the header.  Attributes in the ``.cpp`` file are not visible outside of the646immediate translation unit, which leads to false negatives and false positives.647 648 649(Q) "*Mutex is not locked on every path through here?*"  What does that mean?650 651(A) See :ref:`conditional_locks`, below.652 653 654.. _limitations:655 656Known Limitations657=================658 659Lexical scope660-------------661 662Thread safety attributes contain ordinary C++ expressions, and thus follow663ordinary C++ scoping rules.  In particular, this means that mutexes and other664capabilities must be declared before they can be used in an attribute.665Use-before-declaration is okay within a single class, because attributes are666parsed at the same time as method bodies. (C++ delays parsing of method bodies667until the end of the class.)  However, use-before-declaration is not allowed668between classes, as illustrated below.669 670.. code-block:: c++671 672  class Foo;673 674  class Bar {675    void bar(Foo* f) REQUIRES(f->mu);  // Error: mu undeclared.676  };677 678  class Foo {679    Mutex mu;680  };681 682 683Private Mutexes684---------------685 686Good software engineering practice dictates that mutexes should be private687members because the locking mechanism used by a thread-safe class is part of688its internal implementation.  However, private mutexes can sometimes leak into689the public interface of a class.690Thread safety attributes follow normal C++ access restrictions, so if ``mu``691is a private member of ``c``, then it is an error to write ``c.mu`` in an692attribute.693 694One workaround is to (ab)use the ``RETURN_CAPABILITY`` attribute to provide a695public *name* for a private mutex, without actually exposing the underlying696mutex.  For example:697 698.. code-block:: c++699 700  class MyClass {701  private:702    Mutex mu;703 704  public:705    // For thread safety analysis only.  Does not need to be defined.706    Mutex* getMu() RETURN_CAPABILITY(mu);707 708    void doSomething() REQUIRES(mu);709  };710 711  void doSomethingTwice(MyClass& c) REQUIRES(c.getMu()) {712    // The analysis thinks that c.getMu() == c.mu713    c.doSomething();714    c.doSomething();715  }716 717In the above example, ``doSomethingTwice()`` is an external routine that718requires ``c.mu`` to be locked, which cannot be declared directly because ``mu``719is private.  This pattern is discouraged because it720violates encapsulation, but it is sometimes necessary, especially when adding721annotations to an existing code base.  The workaround is to define ``getMu()``722as a fake getter method, which is provided only for the benefit of thread723safety analysis.724 725 726.. _conditional_locks:727 728No conditionally held locks.729----------------------------730 731The analysis must be able to determine whether a lock is held, or not held, at732every program point.  Thus, sections of code where a lock *might be held* will733generate spurious warnings (false positives).  For example:734 735.. code-block:: c++736 737  void foo() {738    bool b = needsToLock();739    if (b) mu.Lock();740    ...  // Warning!  Mutex 'mu' is not held on every path through here.741    if (b) mu.Unlock();742  }743 744 745No checking inside constructors and destructors.746------------------------------------------------747 748The analysis currently does not do any checking inside constructors or749destructors.  In other words, every constructor and destructor is treated as750if it was annotated with ``NO_THREAD_SAFETY_ANALYSIS``.751The reason for this is that during initialization, only one thread typically752has access to the object which is being initialized, and it is thus safe (and753common practice) to initialize guarded members without acquiring any locks.754The same is true of destructors.755 756Ideally, the analysis would allow initialization of guarded members inside the757object being initialized or destroyed, while still enforcing the usual access758restrictions on everything else.  However, this is difficult to enforce in759practice, because in complex pointer-based data structures, it is hard to760determine what data is owned by the enclosing object.761 762No inlining.763------------764 765Thread safety analysis is strictly intra-procedural, just like ordinary type766checking.  It relies only on the declared attributes of a function, and will767not attempt to inline any method calls.  As a result, code such as the768following will not work:769 770.. code-block:: c++771 772  template<class T>773  class AutoCleanup {774    T* object;775    void (T::*mp)();776 777  public:778    AutoCleanup(T* obj, void (T::*imp)()) : object(obj), mp(imp) { }779    ~AutoCleanup() { (object->*mp)(); }780  };781 782  Mutex mu;783  void foo() {784    mu.Lock();785    AutoCleanup<Mutex>(&mu, &Mutex::Unlock);786    // ...787  }  // Warning, mu is not unlocked.788 789In this case, the destructor of ``Autocleanup`` calls ``mu.Unlock()``, so790the warning is bogus.  However,791thread safety analysis cannot see the unlock, because it does not attempt to792inline the destructor.  Moreover, there is no way to annotate the destructor,793because the destructor is calling a function that is not statically known.794This pattern is simply not supported.795 796 797No alias analysis.798------------------799 800The analysis currently does not track pointer aliases.  Thus, there can be801false positives if two pointers both point to the same mutex.802 803 804.. code-block:: c++805 806  class MutexUnlocker {807    Mutex* mu;808 809  public:810    MutexUnlocker(Mutex* m) RELEASE(m) : mu(m)  { mu->Unlock(); }811    ~MutexUnlocker() ACQUIRE(mu) { mu->Lock(); }812  };813 814  Mutex mutex;815  void test() REQUIRES(mutex) {816    {817      MutexUnlocker munl(&mutex);  // unlocks mutex818      doSomeIO();819    }                              // Warning: locks munl.mu820  }821 822The MutexUnlocker class is intended to be the dual of the MutexLocker class,823defined in :ref:`mutexheader`.  However, it doesn't work because the analysis824doesn't know that munl.mu == mutex.  The SCOPED_CAPABILITY attribute handles825aliasing for MutexLocker, but does so only for that particular pattern.826 827 828.. _mutexheader:829 830mutex.h831=======832 833Thread safety analysis can be used with any threading library, but it does834require that the threading API be wrapped in classes and methods which have the835appropriate annotations.  The following code provides ``mutex.h`` as an example;836these methods should be filled in to call the appropriate underlying837implementation.838 839 840.. code-block:: c++841 842 843  #ifndef THREAD_SAFETY_ANALYSIS_MUTEX_H844  #define THREAD_SAFETY_ANALYSIS_MUTEX_H845 846  // Enable thread safety attributes only with clang.847  // The attributes can be safely erased when compiling with other compilers.848  #if defined(__clang__) && (!defined(SWIG))849  #define THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))850  #else851  #define THREAD_ANNOTATION_ATTRIBUTE__(x)   // no-op852  #endif853 854  #define CAPABILITY(x) \855    THREAD_ANNOTATION_ATTRIBUTE__(capability(x))856 857  #define REENTRANT_CAPABILITY \858    THREAD_ANNOTATION_ATTRIBUTE__(reentrant_capability)859 860  #define SCOPED_CAPABILITY \861    THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)862 863  #define GUARDED_BY(x) \864    THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))865 866  #define PT_GUARDED_BY(x) \867    THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))868 869  #define ACQUIRED_BEFORE(...) \870    THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))871 872  #define ACQUIRED_AFTER(...) \873    THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))874 875  #define REQUIRES(...) \876    THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))877 878  #define REQUIRES_SHARED(...) \879    THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))880 881  #define ACQUIRE(...) \882    THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))883 884  #define ACQUIRE_SHARED(...) \885    THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))886 887  #define RELEASE(...) \888    THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))889 890  #define RELEASE_SHARED(...) \891    THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))892 893  #define RELEASE_GENERIC(...) \894    THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))895 896  #define TRY_ACQUIRE(...) \897    THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))898 899  #define TRY_ACQUIRE_SHARED(...) \900    THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))901 902  #define EXCLUDES(...) \903    THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))904 905  #define ASSERT_CAPABILITY(x) \906    THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))907 908  #define ASSERT_SHARED_CAPABILITY(x) \909    THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))910 911  #define RETURN_CAPABILITY(x) \912    THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))913 914  #define NO_THREAD_SAFETY_ANALYSIS \915    THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)916 917 918  // Defines an annotated interface for mutexes.919  // These methods can be implemented to use any internal mutex implementation.920  class CAPABILITY("mutex") Mutex {921  public:922    // Acquire/lock this mutex exclusively.  Only one thread can have exclusive923    // access at any one time.  Write operations to guarded data require an924    // exclusive lock.925    void Lock() ACQUIRE();926 927    // Acquire/lock this mutex for read operations, which require only a shared928    // lock.  This assumes a multiple-reader, single writer semantics.  Multiple929    // threads may acquire the mutex simultaneously as readers, but a writer930    // must wait for all of them to release the mutex before it can acquire it931    // exclusively.932    void ReaderLock() ACQUIRE_SHARED();933 934    // Release/unlock an exclusive mutex.935    void Unlock() RELEASE();936 937    // Release/unlock a shared mutex.938    void ReaderUnlock() RELEASE_SHARED();939 940    // Generic unlock, can unlock exclusive and shared mutexes.941    void GenericUnlock() RELEASE_GENERIC();942 943    // Try to acquire the mutex.  Returns true on success, and false on failure.944    bool TryLock() TRY_ACQUIRE(true);945 946    // Try to acquire the mutex for read operations.947    bool ReaderTryLock() TRY_ACQUIRE_SHARED(true);948 949    // Assert that this mutex is currently held by the calling thread.950    void AssertHeld() ASSERT_CAPABILITY(this);951 952    // Assert that is mutex is currently held for read operations.953    void AssertReaderHeld() ASSERT_SHARED_CAPABILITY(this);954 955    // For negative capabilities.956    const Mutex& operator!() const { return *this; }957  };958 959  // Tag types for selecting a constructor.960  struct adopt_lock_t {} inline constexpr adopt_lock = {};961  struct defer_lock_t {} inline constexpr defer_lock = {};962  struct shared_lock_t {} inline constexpr shared_lock = {};963 964  // MutexLocker is an RAII class that acquires a mutex in its constructor, and965  // releases it in its destructor.966  class SCOPED_CAPABILITY MutexLocker {967  private:968    Mutex* mut;969    bool locked;970 971  public:972    // Acquire mu, implicitly acquire *this and associate it with mu.973    MutexLocker(Mutex *mu) ACQUIRE(mu) : mut(mu), locked(true) {974      mu->Lock();975    }976 977    // Assume mu is held, implicitly acquire *this and associate it with mu.978    MutexLocker(Mutex *mu, adopt_lock_t) REQUIRES(mu) : mut(mu), locked(true) {}979 980    // Acquire mu in shared mode, implicitly acquire *this and associate it with mu.981    MutexLocker(Mutex *mu, shared_lock_t) ACQUIRE_SHARED(mu) : mut(mu), locked(true) {982      mu->ReaderLock();983    }984 985    // Assume mu is held in shared mode, implicitly acquire *this and associate it with mu.986    MutexLocker(Mutex *mu, adopt_lock_t, shared_lock_t) REQUIRES_SHARED(mu)987      : mut(mu), locked(true) {}988 989    // Assume mu is not held, implicitly acquire *this and associate it with mu.990    MutexLocker(Mutex *mu, defer_lock_t) EXCLUDES(mu) : mut(mu), locked(false) {}991 992    // Same as constructors, but without tag types. (Requires C++17 copy elision.)993    static MutexLocker Lock(Mutex *mu) ACQUIRE(mu) {994      return MutexLocker(mu);995    }996 997    static MutexLocker Adopt(Mutex *mu) REQUIRES(mu) {998      return MutexLocker(mu, adopt_lock);999    }1000 1001    static MutexLocker ReaderLock(Mutex *mu) ACQUIRE_SHARED(mu) {1002      return MutexLocker(mu, shared_lock);1003    }1004 1005    static MutexLocker AdoptReaderLock(Mutex *mu) REQUIRES_SHARED(mu) {1006      return MutexLocker(mu, adopt_lock, shared_lock);1007    }1008 1009    static MutexLocker DeferLock(Mutex *mu) EXCLUDES(mu) {1010      return MutexLocker(mu, defer_lock);1011    }1012 1013    // Release *this and all associated mutexes, if they are still held.1014    // There is no warning if the scope was already unlocked before.1015    ~MutexLocker() RELEASE() {1016      if (locked)1017        mut->GenericUnlock();1018    }1019 1020    // Acquire all associated mutexes exclusively.1021    void Lock() ACQUIRE() {1022      mut->Lock();1023      locked = true;1024    }1025 1026    // Try to acquire all associated mutexes exclusively.1027    bool TryLock() TRY_ACQUIRE(true) {1028      return locked = mut->TryLock();1029    }1030 1031    // Acquire all associated mutexes in shared mode.1032    void ReaderLock() ACQUIRE_SHARED() {1033      mut->ReaderLock();1034      locked = true;1035    }1036 1037    // Try to acquire all associated mutexes in shared mode.1038    bool ReaderTryLock() TRY_ACQUIRE_SHARED(true) {1039      return locked = mut->ReaderTryLock();1040    }1041 1042    // Release all associated mutexes. Warn on double unlock.1043    void Unlock() RELEASE() {1044      mut->Unlock();1045      locked = false;1046    }1047 1048    // Release all associated mutexes. Warn on double unlock.1049    void ReaderUnlock() RELEASE() {1050      mut->ReaderUnlock();1051      locked = false;1052    }1053  };1054 1055 1056  #ifdef USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES1057  // The original version of thread safety analysis the following attribute1058  // definitions.  These use a lock-based terminology.  They are still in use1059  // by existing thread safety code, and will continue to be supported.1060 1061  // Deprecated.1062  #define PT_GUARDED_VAR \1063    THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_var)1064 1065  // Deprecated.1066  #define GUARDED_VAR \1067    THREAD_ANNOTATION_ATTRIBUTE__(guarded_var)1068 1069  // Replaced by REQUIRES1070  #define EXCLUSIVE_LOCKS_REQUIRED(...) \1071    THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))1072 1073  // Replaced by REQUIRES_SHARED1074  #define SHARED_LOCKS_REQUIRED(...) \1075    THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))1076 1077  // Replaced by CAPABILITY1078  #define LOCKABLE \1079    THREAD_ANNOTATION_ATTRIBUTE__(lockable)1080 1081  // Replaced by SCOPED_CAPABILITY1082  #define SCOPED_LOCKABLE \1083    THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)1084 1085  // Replaced by ACQUIRE1086  #define EXCLUSIVE_LOCK_FUNCTION(...) \1087    THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))1088 1089  // Replaced by ACQUIRE_SHARED1090  #define SHARED_LOCK_FUNCTION(...) \1091    THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))1092 1093  // Replaced by RELEASE and RELEASE_SHARED1094  #define UNLOCK_FUNCTION(...) \1095    THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))1096 1097  // Replaced by TRY_ACQUIRE1098  #define EXCLUSIVE_TRYLOCK_FUNCTION(...) \1099    THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))1100 1101  // Replaced by TRY_ACQUIRE_SHARED1102  #define SHARED_TRYLOCK_FUNCTION(...) \1103    THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))1104 1105  // Replaced by ASSERT_CAPABILITY1106  #define ASSERT_EXCLUSIVE_LOCK(...) \1107    THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))1108 1109  // Replaced by ASSERT_SHARED_CAPABILITY1110  #define ASSERT_SHARED_LOCK(...) \1111    THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))1112 1113  // Replaced by EXCLUDE_CAPABILITY.1114  #define LOCKS_EXCLUDED(...) \1115    THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))1116 1117  // Replaced by RETURN_CAPABILITY1118  #define LOCK_RETURNED(x) \1119    THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))1120 1121  #endif  // USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES1122 1123  #endif  // THREAD_SAFETY_ANALYSIS_MUTEX_H1124