github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/tools/checklocks/state.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package checklocks 16 17 import ( 18 "fmt" 19 "go/token" 20 "go/types" 21 "strings" 22 "sync/atomic" 23 24 "golang.org/x/tools/go/ssa" 25 ) 26 27 // lockState tracks the locking state and aliases. 28 type lockState struct { 29 // lockedMutexes is used to track which mutexes in a given struct are 30 // currently locked. Note that most of the heavy lifting is done by 31 // valueAsString below, which maps to specific structure fields, etc. 32 lockedMutexes []string 33 34 // stored stores values that have been stored in memory, bound to 35 // FreeVars or passed as Parameterse. 36 stored map[ssa.Value]ssa.Value 37 38 // used is a temporary map, used only for valueAsString. It prevents 39 // multiple use of the same memory location. 40 used map[ssa.Value]struct{} 41 42 // defers are the stack of defers that have been pushed. 43 defers []*ssa.Defer 44 45 // refs indicates the number of references on this structure. If it's 46 // greater than one, we will do copy-on-write. 47 refs *int32 48 } 49 50 // newLockState makes a new lockState. 51 func newLockState() *lockState { 52 refs := int32(1) // Not shared. 53 return &lockState{ 54 lockedMutexes: make([]string, 0), 55 used: make(map[ssa.Value]struct{}), 56 stored: make(map[ssa.Value]ssa.Value), 57 defers: make([]*ssa.Defer, 0), 58 refs: &refs, 59 } 60 } 61 62 // fork forks the locking state. When a lockState is forked, any modifications 63 // will cause maps to be copied. 64 func (l *lockState) fork() *lockState { 65 if l == nil { 66 return newLockState() 67 } 68 atomic.AddInt32(l.refs, 1) 69 return &lockState{ 70 lockedMutexes: l.lockedMutexes, 71 used: make(map[ssa.Value]struct{}), 72 stored: l.stored, 73 defers: l.defers, 74 refs: l.refs, 75 } 76 } 77 78 // modify indicates that this state will be modified. 79 func (l *lockState) modify() { 80 if atomic.LoadInt32(l.refs) > 1 { 81 // Copy the lockedMutexes. 82 lm := make([]string, len(l.lockedMutexes)) 83 copy(lm, l.lockedMutexes) 84 l.lockedMutexes = lm 85 86 // Copy the stored values. 87 s := make(map[ssa.Value]ssa.Value) 88 for k, v := range l.stored { 89 s[k] = v 90 } 91 l.stored = s 92 93 // Reset the used values. 94 l.used = make(map[ssa.Value]struct{}) 95 96 // Copy the defers. 97 ds := make([]*ssa.Defer, len(l.defers)) 98 copy(ds, l.defers) 99 l.defers = ds 100 101 // Drop our reference. 102 atomic.AddInt32(l.refs, -1) 103 newRefs := int32(1) // Not shared. 104 l.refs = &newRefs 105 } 106 } 107 108 // isHeld indicates whether the field is held is not. 109 func (l *lockState) isHeld(rv resolvedValue) (string, bool) { 110 if !rv.valid { 111 return rv.valueAsString(l), false 112 } 113 s := rv.valueAsString(l) 114 for _, k := range l.lockedMutexes { 115 if k == s { 116 return s, true 117 } 118 } 119 return s, false 120 } 121 122 // lockField locks the given field. 123 // 124 // If false is returned, the field was already locked. 125 func (l *lockState) lockField(rv resolvedValue) (string, bool) { 126 if !rv.valid { 127 return rv.valueAsString(l), false 128 } 129 s := rv.valueAsString(l) 130 for _, k := range l.lockedMutexes { 131 if k == s { 132 return s, false 133 } 134 } 135 l.modify() 136 l.lockedMutexes = append(l.lockedMutexes, s) 137 return s, true 138 } 139 140 // unlockField unlocks the given field. 141 // 142 // If false is returned, the field was not locked. 143 func (l *lockState) unlockField(rv resolvedValue) (string, bool) { 144 if !rv.valid { 145 return rv.valueAsString(l), false 146 } 147 s := rv.valueAsString(l) 148 for i, k := range l.lockedMutexes { 149 if k == s { 150 // Copy the last lock in and truncate. 151 l.modify() 152 l.lockedMutexes[i] = l.lockedMutexes[len(l.lockedMutexes)-1] 153 l.lockedMutexes = l.lockedMutexes[:len(l.lockedMutexes)-1] 154 return s, true 155 } 156 } 157 return s, false 158 } 159 160 // store records an alias. 161 func (l *lockState) store(addr ssa.Value, v ssa.Value) { 162 l.modify() 163 l.stored[addr] = v 164 } 165 166 // isSubset indicates other holds all the locks held by l. 167 func (l *lockState) isSubset(other *lockState) bool { 168 held := 0 // Number in l, held by other. 169 for _, k := range l.lockedMutexes { 170 for _, ok := range other.lockedMutexes { 171 if k == ok { 172 held++ 173 break 174 } 175 } 176 } 177 return held >= len(l.lockedMutexes) 178 } 179 180 // count indicates the number of locks held. 181 func (l *lockState) count() int { 182 return len(l.lockedMutexes) 183 } 184 185 // isCompatible returns true if the states are compatible. 186 func (l *lockState) isCompatible(other *lockState) bool { 187 return l.isSubset(other) && other.isSubset(l) 188 } 189 190 // elemType is a type that implements the Elem function. 191 type elemType interface { 192 Elem() types.Type 193 } 194 195 // valueAsString returns a string for a given value. 196 // 197 // This decomposes the value into the simplest possible representation in terms 198 // of parameters, free variables and globals. During resolution, stored values 199 // may be transferred, as well as bound free variables. 200 // 201 // Nil may not be passed here. 202 func (l *lockState) valueAsString(v ssa.Value) string { 203 switch x := v.(type) { 204 case *ssa.Parameter: 205 // Was this provided as a paramter for a local anonymous 206 // function invocation? 207 v, ok := l.stored[x] 208 if ok { 209 return l.valueAsString(v) 210 } 211 return fmt.Sprintf("{param:%s}", x.Name()) 212 case *ssa.Global: 213 return fmt.Sprintf("{global:%s}", x.Name()) 214 case *ssa.FreeVar: 215 // Attempt to resolve this, in case we are being invoked in a 216 // scope where all the variables are bound. 217 v, ok := l.stored[x] 218 if ok { 219 // The FreeVar is typically bound to a location, so we 220 // check what's been stored there. Note that the second 221 // may map to the same FreeVar, which we can check. 222 stored, ok := l.stored[v] 223 if ok { 224 return l.valueAsString(stored) 225 } 226 } 227 return fmt.Sprintf("{freevar:%s}", x.Name()) 228 case *ssa.Convert: 229 // Just disregard conversion. 230 return l.valueAsString(x.X) 231 case *ssa.ChangeType: 232 // Ditto, disregard. 233 return l.valueAsString(x.X) 234 case *ssa.UnOp: 235 if x.Op != token.MUL { 236 break 237 } 238 // Is this loading a free variable? If yes, then this can be 239 // resolved in the original isAlias function. 240 if fv, ok := x.X.(*ssa.FreeVar); ok { 241 return l.valueAsString(fv) 242 } 243 // Should be try to resolve via a memory address? This needs to 244 // be done since a memory location can hold its own value. 245 if _, ok := l.used[x.X]; !ok { 246 // Check if we know what the accessed location holds. 247 // This is used to disambiguate memory locations. 248 v, ok := l.stored[x.X] 249 if ok { 250 l.used[x.X] = struct{}{} 251 defer func() { delete(l.used, x.X) }() 252 return l.valueAsString(v) 253 } 254 } 255 // x.X.Type is pointer. We must construct this type 256 // dynamically, since the ssa.Value could be synthetic. 257 return fmt.Sprintf("*(%s)", l.valueAsString(x.X)) 258 case *ssa.Field: 259 structType, ok := resolveStruct(x.X.Type()) 260 if !ok { 261 // This should not happen. 262 panic(fmt.Sprintf("structType not available for struct: %#v", x.X)) 263 } 264 fieldObj := structType.Field(x.Field) 265 return fmt.Sprintf("%s.%s", l.valueAsString(x.X), fieldObj.Name()) 266 case *ssa.FieldAddr: 267 structType, ok := resolveStruct(x.X.Type()) 268 if !ok { 269 // This should not happen. 270 panic(fmt.Sprintf("structType not available for struct: %#v", x.X)) 271 } 272 fieldObj := structType.Field(x.Field) 273 return fmt.Sprintf("&(%s.%s)", l.valueAsString(x.X), fieldObj.Name()) 274 case *ssa.Index: 275 return fmt.Sprintf("%s[%s]", l.valueAsString(x.X), l.valueAsString(x.Index)) 276 case *ssa.IndexAddr: 277 return fmt.Sprintf("&(%s[%s])", l.valueAsString(x.X), l.valueAsString(x.Index)) 278 case *ssa.Lookup: 279 return fmt.Sprintf("%s[%s]", l.valueAsString(x.X), l.valueAsString(x.Index)) 280 case *ssa.Extract: 281 return fmt.Sprintf("%s[%d]", l.valueAsString(x.Tuple), x.Index) 282 } 283 284 // In the case of any other type (e.g. this may be an alloc, a return 285 // value, etc.), just return the literal pointer value to the Value. 286 // This will be unique within the ssa graph, and so if two values are 287 // equal, they are from the same type. 288 return fmt.Sprintf("{%T:%p}", v, v) 289 } 290 291 // String returns the full lock state. 292 func (l *lockState) String() string { 293 if l.count() == 0 { 294 return "no locks held" 295 } 296 return strings.Join(l.lockedMutexes, ",") 297 } 298 299 // pushDefer pushes a defer onto the stack. 300 func (l *lockState) pushDefer(d *ssa.Defer) { 301 l.modify() 302 l.defers = append(l.defers, d) 303 } 304 305 // popDefer pops a defer from the stack. 306 func (l *lockState) popDefer() *ssa.Defer { 307 // Does not technically modify the underlying slice. 308 count := len(l.defers) 309 if count == 0 { 310 return nil 311 } 312 d := l.defers[count-1] 313 l.defers = l.defers[:count-1] 314 return d 315 }