Stephen Hines | 651f13c | 2014-04-23 16:59:28 -0700 | [diff] [blame] | 1 | |
| 2 | ====================== |
| 3 | Thread Safety Analysis |
| 4 | ====================== |
| 5 | |
| 6 | Introduction |
| 7 | ============ |
| 8 | |
| 9 | Clang Thread Safety Analysis is a C++ language extension which warns about |
| 10 | potential race conditions in code. The analysis is completely static (i.e. |
| 11 | compile-time); there is no run-time overhead. The analysis is still |
| 12 | under active development, but it is mature enough to be deployed in an |
| 13 | industrial setting. It being developed by Google, and is used extensively |
| 14 | on their internal code base. |
| 15 | |
| 16 | Thread safety analysis works very much like a type system for multi-threaded |
| 17 | programs. In addition to declaring the *type* of data (e.g. ``int``, ``float``, |
| 18 | etc.), the programmer can (optionally) declare how access to that data is |
| 19 | controlled in a multi-threaded environment. For example, if ``foo`` is |
| 20 | *guarded by* the mutex ``mu``, then the analysis will issue a warning whenever |
| 21 | a piece of code reads or writes to ``foo`` without first locking ``mu``. |
| 22 | Similarly, if there are particular routines that should only be called by |
| 23 | the GUI thread, then the analysis will warn if other threads call those |
| 24 | routines. |
| 25 | |
| 26 | Getting Started |
| 27 | ---------------- |
| 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) EXCLUSIVE_LOCKS_REQUIRED(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 | |
| 60 | This example demonstrates the basic concepts behind the analysis. The |
| 61 | ``GUARDED_BY`` attribute declares that a thread must lock ``mu`` before it can |
| 62 | read or write to ``balance``, thus ensuring that the increment and decrement |
| 63 | operations are atomic. Similarly, ``EXCLUSIVE_LOCKS_REQUIRED`` declares that |
| 64 | the calling thread must lock ``mu`` before calling ``withdrawImpl``. |
| 65 | Because the caller is assumed to have locked ``mu``, it is safe to modify |
| 66 | ``balance`` within the body of the method. |
| 67 | |
| 68 | The ``depositImpl()`` method does not have ``EXCLUSIVE_LOCKS_REQUIRED``, so the |
| 69 | analysis issues a warning. Thread safety analysis is not inter-procedural, so |
| 70 | caller requirements must be explicitly declared. |
| 71 | There is also a warning in ``transferFrom()``, because although the method |
| 72 | locks ``this->mu``, it does not lock ``b.mu``. The analysis understands |
| 73 | that these are two separate mutexes, in two different objects. |
| 74 | |
| 75 | Finally, there is a warning in the ``withdraw()`` method, because it fails to |
| 76 | unlock ``mu``. Every lock must have a corresponding unlock, and the analysis |
| 77 | will detect both double locks, and double unlocks. A function is allowed to |
| 78 | acquire a lock without releasing it, (or vice versa), but it must be annotated |
| 79 | as such (using ``LOCK``/``UNLOCK_FUNCTION``). |
| 80 | |
| 81 | |
| 82 | Running The Analysis |
| 83 | -------------------- |
| 84 | |
| 85 | To run the analysis, simply compile with the ``-Wthread-safety`` flag, e.g. |
| 86 | |
| 87 | .. code-block:: bash |
| 88 | |
| 89 | clang -c -Wthread-safety example.cpp |
| 90 | |
| 91 | Note that this example assumes the presence of a suitably annotated |
| 92 | :ref:`mutexheader` that declares which methods perform locking, |
| 93 | unlocking, and so on. |
| 94 | |
| 95 | |
| 96 | Basic Concepts: Capabilities |
| 97 | ============================ |
| 98 | |
| 99 | Thread safety analysis provides a way of protecting *resources* with |
| 100 | *capabilities*. A resource is either a data member, or a function/method |
| 101 | that provides access to some underlying resource. The analysis ensures that |
| 102 | the calling thread cannot access the *resource* (i.e. call the function, or |
| 103 | read/write the data) unless it has the *capability* to do so. |
| 104 | |
| 105 | Capabilities are associated with named C++ objects which declare specific |
| 106 | methods to acquire and release the capability. The name of the object serves |
| 107 | to identify the capability. The most common example is a mutex. For example, |
| 108 | if ``mu`` is a mutex, then calling ``mu.Lock()`` causes the calling thread |
| 109 | to acquire the capability to access data that is protected by ``mu``. Similarly, |
| 110 | calling ``mu.Unlock()`` releases that capability. |
| 111 | |
| 112 | A thread may hold a capability either *exclusively* or *shared*. An exclusive |
| 113 | capability can be held by only one thread at a time, while a shared capability |
| 114 | can be held by many threads at the same time. This mechanism enforces a |
| 115 | multiple-reader, single-writer pattern. Write operations to protected data |
| 116 | require exclusive access, while read operations require only shared access. |
| 117 | |
| 118 | At any given moment during program execution, a thread holds a specific set of |
| 119 | capabilities (e.g. the set of mutexes that it has locked.) These act like keys |
| 120 | or tokens that allow the thread to access a given resource. Just like physical |
| 121 | security keys, a thread cannot make copy of a capability, nor can it destroy |
| 122 | one. A thread can only release a capability to another thread, or acquire one |
| 123 | from another thread. The annotations are deliberately agnostic about the |
| 124 | exact mechanism used to acquire and release capabilities; it assumes that the |
| 125 | underlying implementation (e.g. the Mutex implementation) does the handoff in |
| 126 | an appropriate manner. |
| 127 | |
| 128 | The set of capabilities that are actually held by a given thread at a given |
| 129 | point in program execution is a run-time concept. The static analysis works |
| 130 | by calculating an approximation of that set, called the *capability |
| 131 | environment*. The capability environment is calculated for every program point, |
| 132 | and describes the set of capabilities that are statically known to be held, or |
| 133 | not held, at that particular point. This environment is a conservative |
| 134 | approximation of the full set of capabilities that will actually held by a |
| 135 | thread at run-time. |
| 136 | |
| 137 | |
| 138 | Reference Guide |
| 139 | =============== |
| 140 | |
| 141 | The thread safety analysis uses attributes to declare threading constraints. |
| 142 | Attributes must be attached to named declarations, such as classes, methods, |
| 143 | and data members. Users are *strongly advised* to define macros for the various |
| 144 | attributes; example definitions can be found in :ref:`mutexheader`, below. |
| 145 | The following documentation assumes the use of macros. |
| 146 | |
| 147 | |
| 148 | GUARDED_BY(c) and PT_GUARDED_BY(c) |
| 149 | ---------------------------------- |
| 150 | |
| 151 | ``GUARDED_BY`` is an attribute on data members, which declares that the data |
| 152 | member is protected by the given capability. Read operations on the data |
| 153 | require shared access, while write operations require exclusive access. |
| 154 | |
| 155 | ``PT_GUARDED_BY`` is similar, but is intended for use on pointers and smart |
| 156 | pointers. There is no constraint on the data member itself, but the *data that |
| 157 | it points to* is protected by the given capability. |
| 158 | |
| 159 | .. code-block:: c++ |
| 160 | |
| 161 | Mutex mu; |
| 162 | int *p1 GUARDED_BY(mu); |
| 163 | int *p2 PT_GUARDED_BY(mu); |
| 164 | unique_ptr<int> p3 PT_GUARDED_BY(mu); |
| 165 | |
| 166 | void test() { |
| 167 | p1 = 0; // Warning! |
| 168 | |
| 169 | p2 = new int; // OK. |
| 170 | *p2 = 42; // Warning! |
| 171 | |
| 172 | p3.reset(new int); // OK. |
| 173 | *p3 = 42; // Warning! |
| 174 | } |
| 175 | |
| 176 | |
| 177 | EXCLUSIVE_LOCKS_REQUIRED(...), SHARED_LOCKS_REQUIRED(...) |
| 178 | --------------------------------------------------------- |
| 179 | |
| 180 | ``EXCLUSIVE_LOCKS_REQUIRED`` is an attribute on functions or methods, which |
| 181 | declares that the calling thread must have exclusive access to the given |
| 182 | capabilities. More than one capability may be specified. The capabilities |
| 183 | must be held on entry to the function, *and must still be held on exit*. |
| 184 | |
| 185 | ``SHARED_LOCKS_REQUIRED`` is similar, but requires only shared access. |
| 186 | |
| 187 | .. code-block:: c++ |
| 188 | |
| 189 | Mutex mu1, mu2; |
| 190 | int a GUARDED_BY(mu1); |
| 191 | int b GUARDED_BY(mu2); |
| 192 | |
| 193 | void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { |
| 194 | a = 0; |
| 195 | b = 0; |
| 196 | } |
| 197 | |
| 198 | void test() { |
| 199 | mu1.Lock(); |
| 200 | foo(); // Warning! Requires mu2. |
| 201 | mu1.Unlock(); |
| 202 | } |
| 203 | |
| 204 | |
| 205 | EXCLUSIVE_LOCK_FUNCTION(...), SHARED_LOCK_FUNCTION(...), UNLOCK_FUNCTION(...) |
| 206 | ----------------------------------------------------------------------------- |
| 207 | |
| 208 | ``EXCLUSIVE_LOCK_FUNCTION`` is an attribute on functions or methods, which |
| 209 | declares that the function acquires a capability, but does not release it. The |
| 210 | caller must not hold the given capability on entry, and it will hold the |
| 211 | capability on exit. ``SHARED_LOCK_FUNCTION`` is similar. |
| 212 | |
| 213 | ``UNLOCK_FUNCTION`` declares that the function releases the given capability. |
| 214 | The caller must hold the capability on entry, and will no longer hold it on |
| 215 | exit. It does not matter whether the given capability is shared or exclusive. |
| 216 | |
| 217 | .. code-block:: c++ |
| 218 | |
| 219 | Mutex mu; |
| 220 | MyClass myObject GUARDED_BY(mu); |
| 221 | |
| 222 | void lockAndInit() EXCLUSIVE_LOCK_FUNCTION(mu) { |
| 223 | mu.Lock(); |
| 224 | myObject.init(); |
| 225 | } |
| 226 | |
| 227 | void cleanupAndUnlock() UNLOCK_FUNCTION(mu) { |
| 228 | myObject.cleanup(); |
| 229 | } // Warning! Need to unlock mu. |
| 230 | |
| 231 | void test() { |
| 232 | lockAndInit(); |
| 233 | myObject.doSomething(); |
| 234 | cleanupAndUnlock(); |
| 235 | myObject.doSomething(); // Warning, mu is not locked. |
| 236 | } |
| 237 | |
| 238 | If no argument is passed to ``(UN)LOCK_FUNCTION``, then the argument is assumed |
| 239 | to be ``this``, and the analysis will not check the body of the function. This |
| 240 | pattern is intended for use by classes which hide locking details behind an |
| 241 | abstract interface. E.g. |
| 242 | |
| 243 | .. code-block:: c++ |
| 244 | |
| 245 | template <class T> |
| 246 | class LOCKABLE Container { |
| 247 | private: |
| 248 | Mutex mu; |
| 249 | T* data; |
| 250 | |
| 251 | public: |
| 252 | // Hide mu from public interface. |
| 253 | void Lock() EXCLUSIVE_LOCK_FUNCTION() { mu.Lock(); } |
| 254 | void Unlock() UNLOCK_FUNCTION() { mu.Unlock(); } |
| 255 | |
| 256 | T& getElem(int i) { return data[i]; } |
| 257 | }; |
| 258 | |
| 259 | void test() { |
| 260 | Container<int> c; |
| 261 | c.Lock(); |
| 262 | int i = c.getElem(0); |
| 263 | c.Unlock(); |
| 264 | } |
| 265 | |
| 266 | |
| 267 | LOCKS_EXCLUDED(...) |
| 268 | ------------------- |
| 269 | |
| 270 | ``LOCKS_EXCLUDED`` is an attribute on functions or methods, which declares that |
| 271 | the caller must *not* hold the given capabilities. This annotation is |
| 272 | used to prevent deadlock. Many mutex implementations are not re-entrant, so |
| 273 | deadlock can occur if the function in question acquires the mutex a second time. |
| 274 | |
| 275 | .. code-block:: c++ |
| 276 | |
| 277 | Mutex mu; |
| 278 | int a GUARDED_BY(mu); |
| 279 | |
| 280 | void clear() LOCKS_EXCLUDED(mu) { |
| 281 | mu.Lock(); |
| 282 | a = 0; |
| 283 | mu.Unlock(); |
| 284 | } |
| 285 | |
| 286 | void reset() { |
| 287 | mu.Lock(); |
| 288 | clear(); // Warning! Caller cannot hold 'mu'. |
| 289 | mu.Unlock(); |
| 290 | } |
| 291 | |
| 292 | Unlike ``LOCKS_REQUIRED``, ``LOCKS_EXCLUDED`` is optional. The analysis will |
| 293 | not issue a warning if the attribute is missing. See :ref:`limitations`. |
| 294 | |
| 295 | |
| 296 | NO_THREAD_SAFETY_ANALYSIS |
| 297 | ------------------------- |
| 298 | |
| 299 | ``NO_THREAD_SAFETY_ANALYSIS`` is an attribute on functions or methods, which |
| 300 | turns off thread safety checking for that method. It provides an escape hatch |
| 301 | for functions which are either (1) deliberately thread-unsafe, or (2) are |
| 302 | thread-safe, but too complicated for the analysis to understand. Reasons for |
| 303 | (2) will be described in the :ref:`limitations`, below. |
| 304 | |
| 305 | .. code-block:: c++ |
| 306 | |
| 307 | class Counter { |
| 308 | Mutex mu; |
| 309 | int a GUARDED_BY(mu); |
| 310 | |
| 311 | void unsafeIncrement() NO_THREAD_SAFETY_ANALYSIS { a++; } |
| 312 | }; |
| 313 | |
| 314 | |
| 315 | LOCK_RETURNED(c) |
| 316 | ---------------- |
| 317 | |
| 318 | ``LOCK_RETURNED`` is an attribute on functions or methods, which declares that |
| 319 | the function returns a reference to the given capability. It is used to |
| 320 | annotate getter methods that return mutexes. |
| 321 | |
| 322 | .. code-block:: c++ |
| 323 | |
| 324 | class MyClass { |
| 325 | private: |
| 326 | Mutex mu; |
| 327 | int a GUARDED_BY(mu); |
| 328 | |
| 329 | public: |
| 330 | Mutex* getMu() LOCK_RETURNED(mu) { return μ } |
| 331 | |
| 332 | // analysis knows that getMu() == mu |
| 333 | void clear() EXCLUSIVE_LOCKS_REQUIRED(getMu()) { a = 0; } |
| 334 | }; |
| 335 | |
| 336 | |
| 337 | ACQUIRED_BEFORE(...), ACQUIRED_AFTER(...) |
| 338 | ----------------------------------------- |
| 339 | |
| 340 | ``ACQUIRED_BEFORE`` and ``ACQUIRED_AFTER`` are attributes on member |
| 341 | declarations, specifically declarations of mutexes or other capabilities. |
| 342 | These declarations enforce a particular order in which the mutexes must be |
| 343 | acquired, in order to prevent deadlock. |
| 344 | |
| 345 | .. code-block:: c++ |
| 346 | |
| 347 | Mutex m1; |
| 348 | Mutex m2 ACQUIRED_AFTER(m1); |
| 349 | |
| 350 | // Alternative declaration |
| 351 | // Mutex m2; |
| 352 | // Mutex m1 ACQUIRED_BEFORE(m2); |
| 353 | |
| 354 | void foo() { |
| 355 | m2.Lock(); |
| 356 | m1.Lock(); // Warning! m2 must be acquired after m1. |
| 357 | m1.Unlock(); |
| 358 | m2.Unlock(); |
| 359 | } |
| 360 | |
| 361 | |
| 362 | LOCKABLE |
| 363 | -------- |
| 364 | |
| 365 | ``LOCKABLE`` is an attribute on classes, which specifies that objects of the |
| 366 | class can be used as a capability. See the ``Container`` example given above, |
| 367 | or the ``Mutex`` class in :ref:`mutexheader`. |
| 368 | |
| 369 | |
| 370 | SCOPED_LOCKABLE |
| 371 | --------------- |
| 372 | |
| 373 | ``SCOPED_LOCKABLE`` is an attribute on classes that implement RAII-style |
| 374 | locking, in which a capability is acquired in the constructor, and released in |
| 375 | the destructor. Such classes require special handling because the constructor |
| 376 | and destructor refer to the capability via different names; see the |
| 377 | ``MutexLocker`` class in :ref:`mutexheader`, below. |
| 378 | |
| 379 | |
| 380 | EXCLUSIVE_TRYLOCK_FUNCTION(<bool>, ...), SHARED_TRYLOCK_FUNCTION(<bool>, ...) |
| 381 | ----------------------------------------------------------------------------- |
| 382 | |
| 383 | These are attributes on a function or method that tries to acquire the given |
| 384 | capability, and returns a boolean value indicating success or failure. |
| 385 | The first argument must be ``true`` or ``false``, to specify which return value |
| 386 | indicates success, and the remaining arguments are interpreted in the same way |
| 387 | as ``(UN)LOCK_FUNCTION``. See :ref:`mutexheader`, below, for example uses. |
| 388 | |
| 389 | |
| 390 | ASSERT_EXCLUSIVE_LOCK(...) and ASSERT_SHARED_LOCK(...) |
| 391 | ------------------------------------------------------ |
| 392 | |
| 393 | These are attributes on a function or method that does a run-time test to see |
| 394 | whether the calling thread holds the given capability. The function is assumed |
| 395 | to fail (no return) if the capability is not held. See :ref:`mutexheader`, |
| 396 | below, for example uses. |
| 397 | |
| 398 | |
| 399 | GUARDED_VAR and PT_GUARDED_VAR |
| 400 | ------------------------------ |
| 401 | |
| 402 | Use of these attributes has been deprecated. |
| 403 | |
| 404 | |
| 405 | Warning flags |
| 406 | ------------- |
| 407 | |
| 408 | * ``-Wthread-safety``: Umbrella flag which turns on the following three: |
| 409 | |
| 410 | + ``-Wthread-safety-attributes``: Sanity checks on attribute syntax. |
| 411 | + ``-Wthread-safety-analysis``: The core analysis. |
| 412 | + ``-Wthread-safety-precise``: Requires that mutex expressions match precisely. |
| 413 | This warning can be disabled for code which has a lot of aliases. |
| 414 | |
| 415 | When new features and checks are added to the analysis, they can often introduce |
| 416 | additional warnings. Those warnings are initially released as *beta* warnings |
| 417 | for a period of time, after which they are migrated to the standard analysis. |
| 418 | |
| 419 | * ``-Wthread-safety-beta``: New features. Off by default. |
| 420 | |
| 421 | |
| 422 | .. _faq: |
| 423 | |
| 424 | Frequently Asked Questions |
| 425 | ========================== |
| 426 | |
| 427 | (Q) Should I put attributes in the header file, or in the .cc/.cpp/.cxx file? |
| 428 | |
| 429 | (A) Attributes should always go in the header. |
| 430 | |
| 431 | |
| 432 | (Q) "*Mutex is not locked on every path through here?*" What does that mean? |
| 433 | |
| 434 | (A) See :ref:`conditional_locks`, below. |
| 435 | |
| 436 | |
| 437 | .. _limitations: |
| 438 | |
| 439 | Known Limitations |
| 440 | ================= |
| 441 | |
| 442 | Lexical scope |
| 443 | ------------- |
| 444 | |
| 445 | Thread safety attributes contain ordinary C++ expressions, and thus follow |
| 446 | ordinary C++ scoping rules. In particular, this means that mutexes and other |
| 447 | capabilities must be declared before they can be used in an attribute. |
| 448 | Use-before-declaration is okay within a single class, because attributes are |
| 449 | parsed at the same time as method bodies. (C++ delays parsing of method bodies |
| 450 | until the end of the class.) However, use-before-declaration is not allowed |
| 451 | between classes, as illustrated below. |
| 452 | |
| 453 | .. code-block:: c++ |
| 454 | |
| 455 | class Foo; |
| 456 | |
| 457 | class Bar { |
| 458 | void bar(Foo* f) EXCLUSIVE_LOCKS_REQUIRED(f->mu); // Error: mu undeclared. |
| 459 | }; |
| 460 | |
| 461 | class Foo { |
| 462 | Mutex mu; |
| 463 | }; |
| 464 | |
| 465 | |
| 466 | Private Mutexes |
| 467 | --------------- |
| 468 | |
| 469 | Good software engineering practice dictates that mutexes should be private |
| 470 | members, because the locking mechanism used by a thread-safe class is part of |
| 471 | its internal implementation. However, private mutexes can sometimes leak into |
| 472 | the public interface of a class. |
| 473 | Thread safety attributes follow normal C++ access restrictions, so if ``mu`` |
| 474 | is a private member of ``c``, then it is an error to write ``c.mu`` in an |
| 475 | attribute. |
| 476 | |
| 477 | One workround is to (ab)use the ``LOCK_RETURNED`` attribute to provide a public |
| 478 | *name* for a private mutex, without actually exposing the underlying mutex. |
| 479 | For example: |
| 480 | |
| 481 | .. code-block:: c++ |
| 482 | |
| 483 | class MyClass { |
| 484 | private: |
| 485 | Mutex mu; |
| 486 | |
| 487 | public: |
| 488 | // For thread safety analysis only. Does not actually return mu. |
| 489 | Mutex* getMu() LOCK_RETURNED(mu) { return 0; } |
| 490 | |
| 491 | void doSomething() EXCLUSIVE_LOCKS_REQUIRED(mu); |
| 492 | }; |
| 493 | |
| 494 | void doSomethingTwice(MyClass& c) EXCLUSIVE_LOCKS_REQUIRED(c.getMu()) { |
| 495 | // The analysis thinks that c.getMu() == c.mu |
| 496 | c.doSomething(); |
| 497 | c.doSomething(); |
| 498 | } |
| 499 | |
| 500 | In the above example, ``doSomethingTwice()`` is an external routine that |
| 501 | requires ``c.mu`` to be locked, which cannot be declared directly because ``mu`` |
| 502 | is private. This pattern is discouraged because it |
| 503 | violates encapsulation, but it is sometimes necessary, especially when adding |
| 504 | annotations to an existing code base. The workaround is to define ``getMu()`` |
| 505 | as a fake getter method, which is provided only for the benefit of thread |
| 506 | safety analysis. |
| 507 | |
| 508 | |
| 509 | False negatives on pass by reference. |
| 510 | ------------------------------------- |
| 511 | |
| 512 | The current version of the analysis only checks operations which refer to |
| 513 | guarded data members directly by name. If the data members are accessed |
| 514 | indirectly, via a pointer or reference, then no warning is generated. Thus, |
| 515 | no warnings will be generated for the following code: |
| 516 | |
| 517 | .. code-block:: c++ |
| 518 | |
| 519 | Mutex mu; |
| 520 | int a GUARDED_BY(mu); |
| 521 | |
| 522 | void clear(int& ra) { ra = 0; } |
| 523 | |
| 524 | void test() { |
| 525 | int *p = &a; |
| 526 | *p = 0; // No warning. *p is an alias to a. |
| 527 | |
| 528 | clear(a); // No warning. 'a' is passed by reference. |
| 529 | } |
| 530 | |
| 531 | This issue is by far the biggest source of false negatives in the current |
| 532 | version of the analysis. At a fundamental level, the |
| 533 | false negatives are caused by the fact that annotations are attached to data |
| 534 | members, rather than types. The type of ``&a`` should really be |
| 535 | ``int GUARDED_BY(mu)*``, rather than ``int*``, and the statement ``p = &a`` |
| 536 | should thus generate a type error. However, attaching attributes to types |
| 537 | would be an invasive change to the C++ type system, with potential |
| 538 | ramifications with respect to template instantation, function overloading, |
| 539 | and so on. Thus, a complete solution to this issue is simply not feasible. |
| 540 | |
| 541 | Future versions of the analysis will include better support for pointer |
| 542 | alias analysis, along with limited checking of guarded types, in order to |
| 543 | reduce the number of false negatives. |
| 544 | |
| 545 | |
| 546 | .. _conditional_locks: |
| 547 | |
| 548 | No conditionally held locks. |
| 549 | ---------------------------- |
| 550 | |
| 551 | The analysis must be able to determine whether a lock is held, or not held, at |
| 552 | every program point. Thus, sections of code where a lock *might be held* will |
| 553 | generate spurious warnings (false positives). For example: |
| 554 | |
| 555 | .. code-block:: c++ |
| 556 | |
| 557 | void foo() { |
| 558 | bool b = needsToLock(); |
| 559 | if (b) mu.Lock(); |
| 560 | ... // Warning! Mutex 'mu' is not held on every path through here. |
| 561 | if (b) mu.Unlock(); |
| 562 | } |
| 563 | |
| 564 | |
| 565 | No checking inside constructors and destructors. |
| 566 | ------------------------------------------------ |
| 567 | |
| 568 | The analysis currently does not do any checking inside constructors or |
| 569 | destructors. In other words, every constructor and destructor is treated as |
| 570 | if it was annotated with ``NO_THREAD_SAFETY_ANALYSIS``. |
| 571 | The reason for this is that during initialization, only one thread typically |
| 572 | has access to the object which is being initialized, and it is thus safe (and |
| 573 | common practice) to initialize guarded members without acquiring any locks. |
| 574 | The same is true of destructors. |
| 575 | |
| 576 | Ideally, the analysis would allow initialization of guarded members inside the |
| 577 | object being initialized or destroyed, while still enforcing the usual access |
| 578 | restrictions on everything else. However, this is difficult to enforce in |
| 579 | practice, because in complex pointer-based data structures, it is hard to |
| 580 | determine what data is "owned by" the enclosing object. |
| 581 | |
| 582 | No inlining. |
| 583 | ------------ |
| 584 | |
| 585 | Thread safety analysis is strictly intra-procedural, just like ordinary type |
| 586 | checking. It relies only on the declared attributes of a function, and will |
| 587 | not attempt to "step inside", or inline any method calls. As a result, code |
| 588 | such as the following will not work: |
| 589 | |
| 590 | .. code-block:: c++ |
| 591 | |
| 592 | template<class T> |
| 593 | class AutoCleanup { |
| 594 | T* object; |
| 595 | void (T::*mp)(); |
| 596 | |
| 597 | public: |
| 598 | AutoCleanup(T* obj, void (T::*imp)()) : object(obj), mp(imp) { } |
| 599 | ~AutoCleanup() { (object->*mp)(); } |
| 600 | }; |
| 601 | |
| 602 | Mutex mu; |
| 603 | void foo() { |
| 604 | mu.Lock(); |
| 605 | AutoCleanup<Mutex>(&mu, &Mutex::Unlock); |
| 606 | ... |
| 607 | } // Warning, mu is not unlocked. |
| 608 | |
| 609 | In this case, the destructor of ``Autocleanup`` calls ``mu.Unlock()``, so |
| 610 | the warning is bogus. However, |
| 611 | thread safety analysis cannot see the unlock, because it does not attempt to |
| 612 | inline the destructor. Moreover, there is no way to annotate the destructor, |
| 613 | because the destructor is calling a function that is not statically known. |
| 614 | This pattern is simply not supported. |
| 615 | |
| 616 | |
| 617 | LOCKS_EXCLUDED is not transitive. |
| 618 | --------------------------------- |
| 619 | |
| 620 | A function which calls a method marked with LOCKS_EXCLUDED is not required to |
| 621 | put LOCKS_EXCLUDED in its own interface. LOCKS_EXCLUDED behaves differently |
| 622 | from LOCKS_REQUIRED in this respect, and it can result in false negatives: |
| 623 | |
| 624 | .. code-block:: c++ |
| 625 | |
| 626 | class Foo { |
| 627 | Mutex mu; |
| 628 | |
| 629 | void foo() { |
| 630 | mu.Lock(); |
| 631 | bar(); // No warning |
| 632 | mu.Unlock(); |
| 633 | } |
| 634 | |
| 635 | void bar() { baz(); } // No warning. (Should have LOCKS_EXCLUDED(mu).) |
| 636 | |
| 637 | void baz() LOCKS_EXCLUDED(mu); |
| 638 | }; |
| 639 | |
| 640 | The lack of transitivity is due to the fact that LOCKS_EXCLUDED can easily |
| 641 | break encapsulation; it would be a bad idea to require functions to list the |
| 642 | names private locks which happen to be acquired internally. |
| 643 | |
| 644 | |
| 645 | No alias analysis. |
| 646 | ------------------ |
| 647 | |
| 648 | The analysis currently does not track pointer aliases. Thus, there can be |
| 649 | false positives if two pointers both point to the same mutex. |
| 650 | |
| 651 | |
| 652 | .. code-block:: c++ |
| 653 | |
| 654 | class MutexUnlocker { |
| 655 | Mutex* mu; |
| 656 | |
| 657 | public: |
| 658 | MutexUnlocker(Mutex* m) UNLOCK_FUNCTION(m) : mu(m) { mu->Unlock(); } |
| 659 | ~MutexUnlocker() EXCLUSIVE_LOCK_FUNCTION(mu) { mu->Lock(); } |
| 660 | }; |
| 661 | |
| 662 | Mutex mutex; |
| 663 | void test() EXCLUSIVE_LOCKS_REQUIRED(mutex) { |
| 664 | { |
| 665 | MutexUnlocker munl(&mutex); // unlocks mutex |
| 666 | doSomeIO(); |
| 667 | } // Warning: locks munl.mu |
| 668 | } |
| 669 | |
| 670 | The MutexUnlocker class is intended to be the dual of the MutexLocker class, |
| 671 | defined in :ref:`mutexheader`. However, it doesn't work because the analysis |
| 672 | doesn't know that munl.mu == mutex. The SCOPED_LOCKABLE attribute handles |
| 673 | aliasing |
| 674 | |
| 675 | |
| 676 | ACQUIRED_BEFORE(...) and ACQUIRED_AFTER(...) are currently unimplemented. |
| 677 | ------------------------------------------------------------------------- |
| 678 | |
| 679 | To be fixed in a future update. |
| 680 | |
| 681 | |
| 682 | .. _mutexheader: |
| 683 | |
| 684 | mutex.h |
| 685 | ======= |
| 686 | |
| 687 | Thread safety analysis can be used with any threading library, but it does |
| 688 | require that the threading API be wrapped in classes and methods which have the |
| 689 | appropriate annotations. The following code provides ``mutex.h`` as an example; |
| 690 | these methods should be filled in to call the appropriate underlying |
| 691 | implementation. |
| 692 | |
| 693 | |
| 694 | .. code-block:: c++ |
| 695 | |
| 696 | #ifndef THREAD_SAFETY_ANALYSIS_MUTEX_H |
| 697 | #define THREAD_SAFETY_ANALYSIS_MUTEX_H |
| 698 | |
| 699 | // Enable thread safety attributes only with clang. |
| 700 | // The attributes can be safely erased when compiling with other compilers. |
| 701 | #if defined(__clang__) && (!defined(SWIG)) |
| 702 | #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) |
| 703 | #else |
| 704 | #define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op |
| 705 | #endif |
| 706 | |
| 707 | #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) |
| 708 | |
| 709 | #define GUARDED_BY(x) \ |
| 710 | THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) |
| 711 | |
| 712 | #define GUARDED_VAR \ |
| 713 | THREAD_ANNOTATION_ATTRIBUTE__(guarded) |
| 714 | |
| 715 | #define PT_GUARDED_BY(x) \ |
| 716 | THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) |
| 717 | |
| 718 | #define PT_GUARDED_VAR \ |
| 719 | THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded) |
| 720 | |
| 721 | #define ACQUIRED_AFTER(...) \ |
| 722 | THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) |
| 723 | |
| 724 | #define ACQUIRED_BEFORE(...) \ |
| 725 | THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) |
| 726 | |
| 727 | #define EXCLUSIVE_LOCKS_REQUIRED(...) \ |
| 728 | THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) |
| 729 | |
| 730 | #define SHARED_LOCKS_REQUIRED(...) \ |
| 731 | THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) |
| 732 | |
| 733 | #define LOCKS_EXCLUDED(...) \ |
| 734 | THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) |
| 735 | |
| 736 | #define LOCK_RETURNED(x) \ |
| 737 | THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) |
| 738 | |
| 739 | #define LOCKABLE \ |
| 740 | THREAD_ANNOTATION_ATTRIBUTE__(lockable) |
| 741 | |
| 742 | #define SCOPED_LOCKABLE \ |
| 743 | THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) |
| 744 | |
| 745 | #define EXCLUSIVE_LOCK_FUNCTION(...) \ |
| 746 | THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) |
| 747 | |
| 748 | #define SHARED_LOCK_FUNCTION(...) \ |
| 749 | THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) |
| 750 | |
| 751 | #define ASSERT_EXCLUSIVE_LOCK(...) \ |
| 752 | THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) |
| 753 | |
| 754 | #define ASSERT_SHARED_LOCK(...) \ |
| 755 | THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__)) |
| 756 | |
| 757 | #define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ |
| 758 | THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) |
| 759 | |
| 760 | #define SHARED_TRYLOCK_FUNCTION(...) \ |
| 761 | THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) |
| 762 | |
| 763 | #define UNLOCK_FUNCTION(...) \ |
| 764 | THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) |
| 765 | |
| 766 | #define NO_THREAD_SAFETY_ANALYSIS \ |
| 767 | THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) |
| 768 | |
| 769 | |
| 770 | // Defines an annotated interface for mutexes. |
| 771 | // These methods can be implemented to use any internal mutex implementation. |
| 772 | class LOCKABLE Mutex { |
| 773 | public: |
| 774 | // Acquire/lock this mutex exclusively. Only one thread can have exclusive |
| 775 | // access at any one time. Write operations to guarded data require an |
| 776 | // exclusive lock. |
| 777 | void Lock() EXCLUSIVE_LOCK_FUNCTION(); |
| 778 | |
| 779 | // Acquire/lock this mutex for read operations, which require only a shared |
| 780 | // lock. This assumes a multiple-reader, single writer semantics. Multiple |
| 781 | // threads may acquire the mutex simultaneously as readers, but a writer must |
| 782 | // wait for all of them to release the mutex before it can acquire it |
| 783 | // exclusively. |
| 784 | void ReaderLock() SHARED_LOCK_FUNCTION(); |
| 785 | |
| 786 | // Release/unlock the mutex, regardless of whether it is exclusive or shared. |
| 787 | void Unlock() UNLOCK_FUNCTION(); |
| 788 | |
| 789 | // Try to acquire the mutex. Returns true on success, and false on failure. |
| 790 | bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true); |
| 791 | |
| 792 | // Try to acquire the mutex for read operations. |
| 793 | bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true); |
| 794 | |
| 795 | // Assert that this mutex is currently held by the calling thread. |
| 796 | void AssertHeld() ASSERT_EXCLUSIVE_LOCK(); |
| 797 | |
| 798 | // Assert that is mutex is currently held for read operations. |
| 799 | void AssertReaderHeld() ASSERT_SHARED_LOCK(); |
| 800 | }; |
| 801 | |
| 802 | |
| 803 | // MutexLocker is an RAII class that acquires a mutex in its constructor, and |
| 804 | // releases it in its destructor. |
| 805 | class SCOPED_LOCKABLE MutexLocker { |
| 806 | private: |
| 807 | Mutex* mut; |
| 808 | |
| 809 | public: |
| 810 | MutexLocker(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mut(mu) { |
| 811 | mu->Lock(); |
| 812 | } |
| 813 | ~MutexLocker() UNLOCK_FUNCTION() { |
| 814 | mut->Unlock(); |
| 815 | } |
| 816 | }; |
| 817 | |
| 818 | #endif // THREAD_SAFETY_ANALYSIS_MUTEX_H |