github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/tools/checklocks/test/closures.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 test 16 17 func testClosureInvalid(tc *oneGuardStruct) { 18 // This is expected to fail. 19 callClosure(func() { 20 tc.guardedField = 1 // +checklocksfail 21 }) 22 } 23 24 func testClosureUnsupported(tc *oneGuardStruct) { 25 // Locked outside the closure, so may or may not be valid. This cannot 26 // be handled and we should explicitly fail. This can't be handled 27 // because of the call through callClosure, below, which means the 28 // closure will actually be passed as a value somewhere. 29 tc.mu.Lock() 30 callClosure(func() { 31 tc.guardedField = 1 // +checklocksfail 32 }) 33 tc.mu.Unlock() 34 } 35 36 func testClosureValid(tc *oneGuardStruct) { 37 // All locking happens within the closure. This should not present a 38 // problem for analysis. 39 callClosure(func() { 40 tc.mu.Lock() 41 tc.guardedField = 1 42 tc.mu.Unlock() 43 }) 44 } 45 46 func testClosureInline(tc *oneGuardStruct) { 47 // If the closure is being dispatching inline only, then we should be 48 // able to analyze this call and give it a thumbs up. 49 tc.mu.Lock() 50 func() { 51 tc.guardedField = 1 52 }() 53 tc.mu.Unlock() 54 } 55 56 func testAnonymousInvalid(tc *oneGuardStruct) { 57 // Invalid, as per testClosureInvalid above. 58 callAnonymous(func(tc *oneGuardStruct) { 59 tc.guardedField = 1 // +checklocksfail 60 }, tc) 61 } 62 63 func testAnonymousUnsupported(tc *oneGuardStruct) { 64 // Not supportable, as per testClosureUnsupported above. 65 tc.mu.Lock() 66 callAnonymous(func(tc *oneGuardStruct) { 67 tc.guardedField = 1 // +checklocksfail 68 }, tc) 69 tc.mu.Unlock() 70 } 71 72 func testAnonymousValid(tc *oneGuardStruct) { 73 // Valid, as per testClosureValid above. 74 callAnonymous(func(tc *oneGuardStruct) { 75 tc.mu.Lock() 76 tc.guardedField = 1 77 tc.mu.Unlock() 78 }, tc) 79 } 80 81 func testAnonymousInline(tc *oneGuardStruct) { 82 // Unlike the closure case, we are able to dynamically infer the set of 83 // preconditions for the function dispatch and assert that this is 84 // a valid call. 85 tc.mu.Lock() 86 func(tc *oneGuardStruct) { 87 tc.guardedField = 1 88 }(tc) 89 tc.mu.Unlock() 90 } 91 92 //go:noinline 93 func callClosure(fn func()) { 94 fn() 95 } 96 97 //go:noinline 98 func callAnonymous(fn func(*oneGuardStruct), tc *oneGuardStruct) { 99 fn(tc) 100 }