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 μ }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