github.com/google/capslock@v0.2.3-0.20240517042941-dac19fc347c0/testpkgs/transitive/transitive.go (about) 1 // Copyright 2023 Google LLC 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file or at 5 // https://developers.google.com/open-source/licenses/bsd 6 7 // Package transitive is used for testing. 8 package transitive 9 10 import ( 11 "bytes" 12 "math/big" 13 "math/rand" 14 "net" 15 "os" 16 "sort" 17 "strings" 18 "sync" 19 20 "github.com/google/capslock/testpkgs/callnet" 21 "github.com/google/capslock/testpkgs/callos" 22 "github.com/google/capslock/testpkgs/callutf8" 23 "github.com/google/capslock/testpkgs/indirectcalls" 24 _ "github.com/google/capslock/testpkgs/initfn" // for testing 25 "github.com/google/capslock/testpkgs/useasm" 26 "github.com/google/capslock/testpkgs/usecgo" 27 "github.com/google/capslock/testpkgs/usegenerics" 28 "github.com/google/capslock/testpkgs/uselinkname" 29 "github.com/google/capslock/testpkgs/useunsafe" 30 ) 31 32 // MultipleCapabilities transitively calls a function in os, and a cgo function. 33 func MultipleCapabilities() int { 34 return Os() + Cgo() 35 } 36 37 // Net transitively calls a function in net. 38 func Net() int { 39 return callnet.Foo() + 1 40 } 41 42 // Os transitively calls a function in os. 43 func Os() int { 44 return callos.Foo() + 1 45 } 46 47 // Unsafe calls a function which uses an unsafe pointer. 48 func Unsafe() int { 49 return useunsafe.Foo() + 1 50 } 51 52 // Utf8 transitively calls a function in unicode/utf8. 53 func Utf8() int { 54 return callutf8.Foo() + 1 55 } 56 57 // Cgo transitively calls a cgo function. 58 func Cgo() int { 59 return usecgo.Foo() + 1 60 } 61 62 // Indirect transitively calls a function in os via an interface method call. 63 func Indirect() int { 64 return indirectcalls.CallOsViaInterfaceMethod() + 1 65 } 66 67 // InterestingOnceDo calls Do on a sync.Once. The function passed to Do calls 68 // an interesting function in the os package. 69 func InterestingOnceDo() int { 70 var once sync.Once 71 once.Do(func() { callos.Foo() }) 72 return 12345 73 } 74 75 type structContainingOnce struct { 76 a int 77 b sync.Once 78 c int 79 } 80 81 // OnceInStruct calls Do on a sync.Once in a struct field. 82 func OnceInStruct() int { 83 var a structContainingOnce 84 a.b.Do(func() { callos.Foo() }) 85 return 12345 86 } 87 88 // ComplicatedExpressionWithOnce calls Do on a sync.Once using a complicated 89 // but side-effect-free expression. 90 func ComplicatedExpressionWithOnce() int { 91 type ( 92 t1 map[string]any 93 t2 map[int]t1 94 t3 map[complex64]t2 95 t4 struct { 96 a []t3 97 b func() 98 } 99 ) 100 (*(t4{ 101 a: []t3{ 102 t3{ 103 1.5 + 2.5i: t2{ 104 +7*9 ^ 12: t1{ 105 "a" + "b": &structContainingOnce{}, 106 }, 107 }, 108 }, 109 }, 110 b: func() {}, 111 }.a[0:1:1][0:1][0][1.5+2.5i][51]["ab"].(*structContainingOnce))).b.Do( 112 func() { callos.Foo() }) 113 return 0 114 } 115 116 // UninterestingOnceDo calls Do on a sync.Once. The function passed to Do is 117 // not interesting. 118 func UninterestingOnceDo() int { 119 var once sync.Once 120 once.Do(func() {}) 121 return 54321 122 } 123 124 // foo is a type to use with sort.Sort. 125 type foo []int 126 127 func (f foo) Len() int { return len(f) } 128 func (f foo) Swap(x, y int) { f[x], f[y] = f[y], f[x] } 129 func (f foo) Less(x, y int) bool { 130 a := callos.Foo() // interesting 131 return f[x] < a && a <= f[y] 132 } 133 134 // bar is a type to use with sort.Sort. 135 type bar []int 136 137 func (b bar) Len() int { return len(b) } 138 func (b bar) Swap(x, y int) { b[x], b[y] = b[y], b[x] } 139 func (b bar) Less(x, y int) bool { 140 a := callutf8.Foo() // not interesting 141 return b[x] < a && a <= b[y] 142 } 143 144 // InterestingSort calls sort.Sort with an argument whose Less method has an 145 // interesting capability. 146 func InterestingSort() int { 147 f := foo{1, 2} 148 sort.Sort(f) 149 return f[0] 150 } 151 152 // InterestingSortViaFunction calls sort.Sort via a function-valued variable, 153 // The analysis will not be able to analyze the behavior of the sort, but will 154 // report the UNANALYZED capability to inform the user of this. 155 func InterestingSortViaFunction() int { 156 fn := sort.Sort 157 s := foo{1, 2} 158 fn(s) 159 return s[0] 160 } 161 162 // UninterestingSort calls sort.Sort with an argument whose methods have no 163 // interesting capabilities. 164 func UninterestingSort() int { 165 b := bar{1, 2} 166 sort.Sort(b) 167 return b[0] 168 } 169 170 // InterestingSortSlice calls sort.Slice with an argument that has an 171 // interesting capability. 172 func InterestingSortSlice() int { 173 f := bar{1} 174 sort.Slice(f, func(a, b int) bool { os.Getenv("foo"); return false }) 175 return f[0] 176 } 177 178 // UninterestingSortSlice calls sort.Slice with an argument that has no 179 // interesting capabilities. 180 func UninterestingSortSlice() int { 181 f := bar{1} 182 sort.Slice(f, func(a, b int) bool { return false }) 183 return f[0] 184 } 185 186 // InterestingSortSliceNested calls sort.Slice with an argument that itself 187 // calls sort.Slice. The inner sort's function argument has an interesting 188 // capability. 189 func InterestingSortSliceNested() int { 190 f := []bar{bar{1, 2}, bar{3, 4}} 191 sort.Slice(f, func(a, b int) bool { 192 for _, x := range [2]int{a, b} { 193 sort.Slice(f[x], func(a, b int) bool { os.Getenv("foo"); return f[x][a] < f[x][b] }) 194 } 195 return f[a][0] < f[b][0] 196 }) 197 return f[0][0] 198 } 199 200 // UninterestingSortSliceNested calls sort.Slice with an argument that itself 201 // calls sort.Slice. The inner sort's function argument has no interesting 202 // capabilities. 203 func UninterestingSortSliceNested() int { 204 f := []bar{bar{1, 2}, bar{3, 4}} 205 sort.Slice(f, func(a, b int) bool { 206 for _, x := range [2]int{a, b} { 207 sort.Slice(f[x], func(a, b int) bool { return f[x][a] < f[x][b] }) 208 } 209 return f[a][0] < f[b][0] 210 }) 211 return f[0][0] 212 } 213 214 // InterestingSortSliceStable calls sort.SliceStable with an argument that has an 215 // interesting capability. 216 func InterestingSortSliceStable() int { 217 f := bar{1} 218 sort.SliceStable(f, func(a, b int) bool { os.Getenv("foo"); return false }) 219 return f[0] 220 } 221 222 // UninterestingSortSliceStable calls sort.SliceStable with an argument that has no 223 // interesting capabilities. 224 func UninterestingSortSliceStable() int { 225 f := bar{1} 226 sort.SliceStable(f, func(a, b int) bool { return false }) 227 return f[0] 228 } 229 230 // InterestingSyncPool calls Get on a Pool whose New function has an 231 // interesting capability. 232 func InterestingSyncPool() int { 233 p := sync.Pool{New: func() any { 234 x := callos.Foo() // interesting 235 return &x 236 }} 237 return *p.Get().(*int) 238 } 239 240 // UninterestingSyncPool calls Get on a Pool whose New function has no 241 // interesting capabilities. 242 func UninterestingSyncPool() int { 243 p := sync.Pool{New: func() any { 244 x := callutf8.Foo() // not interesting 245 return &x 246 }} 247 return *p.Get().(*int) 248 } 249 250 // Asm calls an assembly function indirectly. 251 func Asm() int { 252 return useasm.Foo() + 1 253 } 254 255 // AllowedAsmInStdlib calls an assembly function indirectly. That function 256 // is categorized as "safe" in interesting.go. 257 func AllowedAsmInStdlib() int { 258 return strings.Index("foo", "f") + bytes.Index([]byte{1, 2, 3}, []byte{4, 5, 6}) 259 } 260 261 // Linkname indirectly calls a function that uses go:linkname. 262 func Linkname() int { 263 return int(uselinkname.Foo()) + 1 264 } 265 266 // CallViaStdlib uses a standard library function to call an interesting 267 // function by passing it as an argument. 268 func CallViaStdlib() int { 269 return strings.IndexFunc("ab", func(r rune) bool { 270 return callnet.Foo() == int(r) 271 }) 272 } 273 274 // a is used as a type argument for a generic function. 275 type a int 276 277 // Baz has the network capability. 278 func (a a) Baz() int { 279 _, err := net.Dial("a", "b") 280 if err == nil { 281 return 1 282 } 283 return 2 284 } 285 286 // CallGenericFunction calls a generic function in another package, using 287 // "a" as a type argument. 288 func CallGenericFunction() int { 289 var a a 290 return usegenerics.Foo(a, 1) + 1 291 } 292 293 // CallGenericFunctionTransitively calls a non-generic function which calls 294 // a generic function. 295 func CallGenericFunctionTransitively() int { 296 return usegenerics.Bar() + 1 297 } 298 299 type src struct{} 300 301 func (s src) Int63() int64 { 302 return int64(callnet.Foo()) 303 } 304 func (s src) Seed(seed int64) { 305 } 306 307 // UseBigIntRand calls an interesting function via a random-number 308 // generator passed to (*math/big.Int).Rand. 309 func UseBigIntRand() int { 310 var s src 311 r := rand.New(s) 312 x := big.NewInt(12345) 313 x = x.Rand(r, x) 314 return int(x.Int64()) 315 }