| // Copyright 2021 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package vulncheck |
| |
| import ( |
| "path" |
| "reflect" |
| "testing" |
| |
| "golang.org/x/tools/go/callgraph/cha" |
| "golang.org/x/tools/go/packages/packagestest" |
| "golang.org/x/tools/go/ssa" |
| "golang.org/x/tools/go/ssa/ssautil" |
| ) |
| |
| // funcNames returns a set of function names for `funcs`. |
| func funcNames(funcs map[*ssa.Function]bool) map[string]bool { |
| fs := make(map[string]bool) |
| for f := range funcs { |
| fs[dbFuncName(f)] = true |
| } |
| return fs |
| } |
| |
| func TestSlicing(t *testing.T) { |
| // test program |
| p := ` |
| package slice |
| |
| func X() {} |
| func Y() {} |
| |
| // not reachable |
| func id(i int) int { |
| return i |
| } |
| |
| // not reachable |
| func inc(i int) int { |
| return i + 1 |
| } |
| |
| func Apply(b bool, h func()) { |
| if b { |
| func() { |
| print("applied") |
| }() |
| return |
| } |
| h() |
| } |
| |
| type I interface { |
| Foo() |
| } |
| |
| type A struct{} |
| |
| func (a A) Foo() {} |
| |
| // not reachable |
| func (a A) Bar() {} |
| |
| type B struct{} |
| |
| func (b B) Foo() {} |
| |
| func debug(s string) { |
| print(s) |
| } |
| |
| func Do(i I, input string) { |
| debug(input) |
| |
| i.Foo() |
| |
| func(x string) { |
| func(l int) { |
| print(l) |
| }(len(x)) |
| }(input) |
| }` |
| |
| e := packagestest.Export(t, packagestest.Modules, []packagestest.Module{ |
| { |
| Name: "some/module", |
| Files: map[string]interface{}{"slice/slice.go": p}, |
| }, |
| }) |
| |
| graph := NewPackageGraph("go1.18") |
| err := graph.LoadPackagesAndMods(e.Config, nil, []string{path.Join(e.Temp(), "/module/slice")}, true) |
| if err != nil { |
| t.Fatal(err) |
| } |
| prog, ssaPkgs := ssautil.AllPackages(graph.TopPkgs(), 0) |
| prog.Build() |
| |
| pkg := ssaPkgs[0] |
| sources := map[*ssa.Function]bool{pkg.Func("Apply"): true, pkg.Func("Do"): true} |
| fs := funcNames(forwardSlice(sources, cha.CallGraph(prog))) |
| want := map[string]bool{ |
| "Apply": true, |
| "Apply$1": true, |
| "X": true, |
| "Y": true, |
| "Do": true, |
| "Do$1": true, |
| "Do$1$1": true, |
| "debug": true, |
| "A.Foo": true, |
| "B.Foo": true, |
| } |
| if !reflect.DeepEqual(want, fs) { |
| t.Errorf("want %v; got %v", want, fs) |
| } |
| } |