github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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 // lockInfo describes a held lock. 28 type lockInfo struct { 29 exclusive bool 30 object types.Object 31 } 32 33 // lockState tracks the locking state and aliases. 34 type lockState struct { 35 // lockedMutexes is used to track which mutexes in a given struct are 36 // currently locked. Note that most of the heavy lifting is done by 37 // valueAndObject below, which maps to specific structure fields, etc. 38 // 39 // The value indicates whether this is an exclusive lock. 40 lockedMutexes map[string]lockInfo 41 42 // stored stores values that have been stored in memory, bound to 43 // FreeVars or passed as Parameterse. 44 stored map[ssa.Value]ssa.Value 45 46 // used is a temporary map, used only for valueAndObject. It prevents 47 // multiple use of the same memory location. 48 used map[ssa.Value]struct{} 49 50 // defers are the stack of defers that have been pushed. 51 defers []*ssa.Defer 52 53 // refs indicates the number of references on this structure. If it's 54 // greater than one, we will do copy-on-write. 55 refs *int32 56 } 57 58 // newLockState makes a new lockState. 59 func newLockState() *lockState { 60 refs := int32(1) // Not shared. 61 return &lockState{ 62 lockedMutexes: make(map[string]lockInfo), 63 used: make(map[ssa.Value]struct{}), 64 stored: make(map[ssa.Value]ssa.Value), 65 defers: make([]*ssa.Defer, 0), 66 refs: &refs, 67 } 68 } 69 70 // fork forks the locking state. When a lockState is forked, any modifications 71 // will cause maps to be copied. 72 func (l *lockState) fork() *lockState { 73 if l == nil { 74 return newLockState() 75 } 76 atomic.AddInt32(l.refs, 1) 77 return &lockState{ 78 lockedMutexes: l.lockedMutexes, 79 used: make(map[ssa.Value]struct{}), 80 stored: l.stored, 81 defers: l.defers, 82 refs: l.refs, 83 } 84 } 85 86 // modify indicates that this state will be modified. 87 func (l *lockState) modify() { 88 if atomic.LoadInt32(l.refs) > 1 { 89 // Copy the lockedMutexes. 90 lm := make(map[string]lockInfo) 91 for k, v := range l.lockedMutexes { 92 lm[k] = v 93 } 94 l.lockedMutexes = lm 95 96 // Copy the stored values. 97 s := make(map[ssa.Value]ssa.Value) 98 for k, v := range l.stored { 99 s[k] = v 100 } 101 l.stored = s 102 103 // Reset the used values. 104 l.used = make(map[ssa.Value]struct{}) 105 106 // Copy the defers. 107 ds := make([]*ssa.Defer, len(l.defers)) 108 copy(ds, l.defers) 109 l.defers = ds 110 111 // Drop our reference. 112 atomic.AddInt32(l.refs, -1) 113 newRefs := int32(1) // Not shared. 114 l.refs = &newRefs 115 } 116 } 117 118 // isHeld indicates whether the field is held is not. 119 // 120 // Precondition: rv must be valid. 121 func (l *lockState) isHeld(rv resolvedValue, exclusiveRequired bool) (string, bool) { 122 if !rv.valid() { 123 panic("invalid resolvedValue passed to isHeld") 124 } 125 s, _ := rv.valueAndObject(l) 126 info, ok := l.lockedMutexes[s] 127 if !ok { 128 return s, false 129 } 130 // Accept a weaker lock if exclusiveRequired is false. 131 if exclusiveRequired && !info.exclusive { 132 return s, false 133 } 134 return s, true 135 } 136 137 // lockField locks the given field. 138 // 139 // If false is returned, the field was already locked. 140 // 141 // Precondition: rv must be valid. 142 func (l *lockState) lockField(rv resolvedValue, exclusive bool) (string, bool) { 143 if !rv.valid() { 144 panic("invalid resolvedValue passed to isHeld") 145 } 146 s, obj := rv.valueAndObject(l) 147 if _, ok := l.lockedMutexes[s]; ok { 148 return s, false 149 } 150 l.modify() 151 l.lockedMutexes[s] = lockInfo{ 152 exclusive: exclusive, 153 object: obj, 154 } 155 return s, true 156 } 157 158 // unlockField unlocks the given field. 159 // 160 // If false is returned, the field was not locked. 161 // 162 // Precondition: rv must be valid. 163 func (l *lockState) unlockField(rv resolvedValue, exclusive bool) (string, bool) { 164 if !rv.valid() { 165 panic("invalid resolvedValue passed to isHeld") 166 } 167 s, _ := rv.valueAndObject(l) 168 info, ok := l.lockedMutexes[s] 169 if !ok { 170 return s, false 171 } 172 if info.exclusive != exclusive { 173 return s, false 174 } 175 l.modify() 176 delete(l.lockedMutexes, s) 177 return s, true 178 } 179 180 // downgradeField downgrades the given field. 181 // 182 // If false was returned, the field was not downgraded. 183 // 184 // Precondition: rv must be valid. 185 func (l *lockState) downgradeField(rv resolvedValue) (string, bool) { 186 if !rv.valid() { 187 panic("invalid resolvedValue passed to isHeld") 188 } 189 s, _ := rv.valueAndObject(l) 190 info, ok := l.lockedMutexes[s] 191 if !ok { 192 return s, false 193 } 194 if !info.exclusive { 195 return s, false 196 } 197 l.modify() 198 info.exclusive = false 199 l.lockedMutexes[s] = info // Downgraded. 200 return s, true 201 } 202 203 // store records an alias. 204 func (l *lockState) store(addr ssa.Value, v ssa.Value) { 205 l.modify() 206 l.stored[addr] = v 207 } 208 209 // isSubset indicates other holds all the locks held by l. 210 func (l *lockState) isSubset(other *lockState) bool { 211 for k, info := range l.lockedMutexes { 212 otherInfo, otherOk := other.lockedMutexes[k] 213 if !otherOk { 214 return false 215 } 216 // Accept weaker locks as a subset. 217 if info.exclusive && !otherInfo.exclusive { 218 return false 219 } 220 } 221 return true 222 } 223 224 // count indicates the number of locks held. 225 func (l *lockState) count() int { 226 return len(l.lockedMutexes) 227 } 228 229 // isCompatible returns true if the states are compatible. 230 func (l *lockState) isCompatible(other *lockState) bool { 231 return l.isSubset(other) && other.isSubset(l) 232 } 233 234 // elemType is a type that implements the Elem function. 235 type elemType interface { 236 Elem() types.Type 237 } 238 239 // valueAndObject returns a string for a given value, along with a source level 240 // object (if available and relevant). 241 // 242 // This decomposes the value into the simplest possible representation in terms 243 // of parameters, free variables and globals. During resolution, stored values 244 // may be transferred, as well as bound free variables. 245 // 246 // Nil may not be passed here. 247 func (l *lockState) valueAndObject(v ssa.Value) (string, types.Object) { 248 switch x := v.(type) { 249 case *ssa.Parameter: 250 // Was this provided as a paramter for a local anonymous 251 // function invocation? 252 v, ok := l.stored[x] 253 if ok { 254 return l.valueAndObject(v) 255 } 256 return fmt.Sprintf("{param:%s}", x.Name()), x.Object() 257 case *ssa.Global: 258 return fmt.Sprintf("{global:%s}", x.Name()), x.Object() 259 case *ssa.FreeVar: 260 // Attempt to resolve this, in case we are being invoked in a 261 // scope where all the variables are bound. 262 v, ok := l.stored[x] 263 if ok { 264 // The FreeVar is typically bound to a location, so we 265 // check what's been stored there. Note that the second 266 // may map to the same FreeVar, which we can check. 267 stored, ok := l.stored[v] 268 if ok { 269 return l.valueAndObject(stored) 270 } 271 } 272 // FreeVar does not have a corresponding source-level object 273 // that we can return here. 274 return fmt.Sprintf("{freevar:%s}", x.Name()), nil 275 case *ssa.Convert: 276 // Just disregard conversion. 277 return l.valueAndObject(x.X) 278 case *ssa.ChangeType: 279 // Ditto, disregard. 280 return l.valueAndObject(x.X) 281 case *ssa.UnOp: 282 if x.Op != token.MUL { 283 break 284 } 285 // Is this loading a free variable? If yes, then this can be 286 // resolved in the original isAlias function. 287 if fv, ok := x.X.(*ssa.FreeVar); ok { 288 return l.valueAndObject(fv) 289 } 290 // Should be try to resolve via a memory address? This needs to 291 // be done since a memory location can hold its own value. 292 if _, ok := l.used[x.X]; !ok { 293 // Check if we know what the accessed location holds. 294 // This is used to disambiguate memory locations. 295 v, ok := l.stored[x.X] 296 if ok { 297 l.used[x.X] = struct{}{} 298 defer func() { delete(l.used, x.X) }() 299 return l.valueAndObject(v) 300 } 301 } 302 // x.X.Type is pointer. We must construct this type 303 // dynamically, since the ssa.Value could be synthetic. 304 s, obj := l.valueAndObject(x.X) 305 return fmt.Sprintf("*(%s)", s), obj 306 case *ssa.Field: 307 structType, ok := resolveStruct(x.X.Type()) 308 if !ok { 309 // This should not happen. 310 panic(fmt.Sprintf("structType not available for struct: %#v", x.X)) 311 } 312 fieldObj := structType.Field(x.Field) 313 s, _ := l.valueAndObject(x.X) 314 return fmt.Sprintf("%s.%s", s, fieldObj.Name()), fieldObj 315 case *ssa.FieldAddr: 316 structType, ok := resolveStruct(x.X.Type()) 317 if !ok { 318 // This should not happen. 319 panic(fmt.Sprintf("structType not available for struct: %#v", x.X)) 320 } 321 fieldObj := structType.Field(x.Field) 322 s, _ := l.valueAndObject(x.X) 323 return fmt.Sprintf("&(%s.%s)", s, fieldObj.Name()), fieldObj 324 case *ssa.Index: 325 s, _ := l.valueAndObject(x.X) 326 i, _ := l.valueAndObject(x.Index) 327 return fmt.Sprintf("%s[%s]", s, i), nil 328 case *ssa.IndexAddr: 329 s, _ := l.valueAndObject(x.X) 330 i, _ := l.valueAndObject(x.Index) 331 return fmt.Sprintf("&(%s[%s])", s, i), nil 332 case *ssa.Lookup: 333 s, _ := l.valueAndObject(x.X) 334 i, _ := l.valueAndObject(x.Index) 335 return fmt.Sprintf("%s[%s]", s, i), nil 336 case *ssa.Extract: 337 s, _ := l.valueAndObject(x.Tuple) 338 return fmt.Sprintf("%s[%d]", s, x.Index), nil 339 } 340 341 // In the case of any other type (e.g. this may be an alloc, a return 342 // value, etc.), just return the literal pointer value to the Value. 343 // This will be unique within the ssa graph, and so if two values are 344 // equal, they are from the same type. 345 return fmt.Sprintf("{%T:%p}", v, v), nil 346 } 347 348 // String returns the full lock state. 349 func (l *lockState) String() string { 350 if l.count() == 0 { 351 return "no locks held" 352 } 353 keys := make([]string, 0, len(l.lockedMutexes)) 354 for k, info := range l.lockedMutexes { 355 // Include the exclusive status of each lock. 356 keys = append(keys, fmt.Sprintf("%s %s", k, exclusiveStr(info.exclusive))) 357 } 358 return strings.Join(keys, ",") 359 } 360 361 // pushDefer pushes a defer onto the stack. 362 func (l *lockState) pushDefer(d *ssa.Defer) { 363 l.modify() 364 l.defers = append(l.defers, d) 365 } 366 367 // popDefer pops a defer from the stack. 368 func (l *lockState) popDefer() *ssa.Defer { 369 // Does not technically modify the underlying slice. 370 count := len(l.defers) 371 if count == 0 { 372 return nil 373 } 374 d := l.defers[count-1] 375 l.defers = l.defers[:count-1] 376 return d 377 }