github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/tools/checklocks/README.md (about)

     1  # CheckLocks Analyzer
     2  
     3  <!--* freshness: { owner: 'gvisor-eng' reviewed: '2021-03-21' } *-->
     4  
     5  Checklocks is an analyzer for lock and atomic constraints. The analyzer relies
     6  on explicit annotations to identify fields that should be checked for access.
     7  
     8  ## Atomic annotations
     9  
    10  Individual struct members may be noted as requiring atomic access. These
    11  annotations are of the form:
    12  
    13  ```go
    14  type foo struct {
    15    // +checkatomic
    16    bar int32
    17  }
    18  ```
    19  
    20  This will ensure that all accesses to bar are atomic, with the exception of
    21  operations on newly allocated objects.
    22  
    23  ## Lock annotations
    24  
    25  Individual struct members may be protected by annotations that indicate locking
    26  requirements for accessing members. These annotations are of the form:
    27  
    28  ```go
    29  type foo struct {
    30      mu sync.Mutex
    31      // +checklocks:mu
    32      bar int
    33  
    34      foo int  // No annotation on foo means it's not guarded by mu.
    35  
    36      secondMu sync.Mutex
    37  
    38      // Multiple annotations indicate that both must be held but the
    39      // checker does not assert any lock ordering.
    40      // +checklocks:secondMu
    41      // +checklocks:mu
    42      foobar int
    43  }
    44  ```
    45  
    46  The checklocks annotation may also apply to functions. For example:
    47  
    48  ```go
    49  // +checklocks:f.mu
    50  func (f *foo) doThingLocked() { }
    51  ```
    52  
    53  This will check that the "f.mu" is locked for any calls, where possible.
    54  
    55  In case of functions which initialize structs that may have annotations one can
    56  use the following annotation on the function to disable reporting by the lock
    57  checker. The lock checker will still track any mutexes acquired or released but
    58  won't report any failures for this function for unguarded field access.
    59  
    60  ```go
    61  // +checklocks:ignore
    62  func newXXX() *X {
    63  ...
    64  }
    65  ```
    66  
    67  ***The checker treats both 'sync.Mutex' and 'sync.RWMutex' identically, i.e, as
    68  a sync.Mutex. The checker does not distinguish between read locks vs. exclusive
    69  locks and treats all locks as exclusive locks***.
    70  
    71  For cases the checker is able to correctly handle today please see test/test.go.
    72  
    73  The checklocks check also flags any invalid annotations where the mutex
    74  annotation refers either to something that is not a 'sync.Mutex' or
    75  'sync.RWMutex' or where the field does not exist at all. This will prevent the
    76  annotations from becoming stale over time as fields are renamed, etc.
    77  
    78  # Currently not supported
    79  
    80  1.  Anonymous functions are not correctly evaluated. The analyzer does not
    81      currently support specifying annotations on anonymous functions as a result
    82      evaluation of a function that accesses protected fields will fail.
    83  
    84  ```go
    85  type A struct {
    86    mu sync.Mutex
    87  
    88    // +checklocks:mu
    89    x int
    90  }
    91  
    92  func abc() {
    93    var a A
    94    f := func()  { a.x = 1 }  <=== This line will be flagged by analyzer
    95    a.mu.Lock()
    96    f()
    97    a.mu.Unlock()
    98  }
    99  ```
   100  
   101  ### Explicitly Not Supported
   102  
   103  1.  Checking for embedded mutexes as sync.Locker rather than directly as
   104      'sync.Mutex'. In other words, the checker will not track mutex Lock and
   105      Unlock() methods where the mutex is behind an interface dispatch.
   106  
   107  An example that we won't handle is shown below (this in fact will fail to
   108  build):
   109  
   110  ```go
   111  type A struct {
   112    mu sync.Locker
   113  
   114    // +checklocks:mu
   115    x int
   116  }
   117  
   118  func abc() {
   119     mu sync.Mutex
   120     a := A{mu: &mu}
   121     a.x = 1 // This won't be flagged by copylocks checker.
   122  }
   123  
   124  ```
   125  
   126  1.  The checker will not support guards on anything other than the cases
   127      described above. For example, global mutexes cannot be referred to by
   128      checklocks. Only struct members can be used.
   129  
   130  2.  The checker will not support checking for lock ordering violations.
   131  
   132  ## Mixed mode
   133  
   134  Some members may allow read-only atomic access, but be protected against writes
   135  by a mutex. Generally, this imposes the following requirements:
   136  
   137  For a read, one of the following must be true:
   138  
   139  1.  A lock held be held.
   140  1.  The access is atomic.
   141  
   142  For a write, both of the following must be true:
   143  
   144  1.  The lock must be held.
   145  1.  The write must be atomic.
   146  
   147  In order to annotate a relevant field, simply apply *both* annotations from
   148  above. For example:
   149  
   150  ```go
   151  type foo struct {
   152    mu sync.Mutex
   153    // +checklocks:mu
   154    // +checkatomic
   155    bar int32
   156  }
   157  ```