gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 // +checklocksignore 57 func testClosureIgnore(tc *oneGuardStruct) { 58 // Inherit the checklocksignore. 59 x := func() { 60 tc.guardedField = 1 61 } 62 x() 63 } 64 65 func testAnonymousInvalid(tc *oneGuardStruct) { 66 // Invalid, as per testClosureInvalid above. 67 callAnonymous(func(tc *oneGuardStruct) { 68 tc.guardedField = 1 // +checklocksfail 69 }, tc) 70 } 71 72 func testAnonymousUnsupported(tc *oneGuardStruct) { 73 // Not supportable, as per testClosureUnsupported above. 74 tc.mu.Lock() 75 callAnonymous(func(tc *oneGuardStruct) { 76 tc.guardedField = 1 // +checklocksfail 77 }, tc) 78 tc.mu.Unlock() 79 } 80 81 func testAnonymousValid(tc *oneGuardStruct) { 82 // Valid, as per testClosureValid above. 83 callAnonymous(func(tc *oneGuardStruct) { 84 tc.mu.Lock() 85 tc.guardedField = 1 86 tc.mu.Unlock() 87 }, tc) 88 } 89 90 func testAnonymousInline(tc *oneGuardStruct) { 91 // Unlike the closure case, we are able to dynamically infer the set of 92 // preconditions for the function dispatch and assert that this is 93 // a valid call. 94 tc.mu.Lock() 95 func(tc *oneGuardStruct) { 96 tc.guardedField = 1 97 }(tc) 98 tc.mu.Unlock() 99 } 100 101 // +checklocksignore 102 func testAnonymousIgnore(tc *oneGuardStruct) { 103 // Inherit the checklocksignore. 104 x := func(tc *oneGuardStruct) { 105 tc.guardedField = 1 106 } 107 x(tc) 108 } 109 110 //go:noinline 111 func callClosure(fn func()) { 112 fn() 113 } 114 115 //go:noinline 116 func callAnonymous(fn func(*oneGuardStruct), tc *oneGuardStruct) { 117 fn(tc) 118 }