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  }