Skip to content

Commit 53a5385

Browse files
committed
internal/vulncheck: compute proper db names for generic functions
These should not include the type parameter/argument. Updates golang/go#63535 Change-Id: Iaae0e587d365f7e26e2361c9814fa1d288d8ad86 Reviewed-on: https://go-review.googlesource.com/c/vuln/+/548016 TryBot-Result: Gopher Robot <gobot@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Run-TryBot: Zvonimir Pavlinovic <zpavlinovic@google.com> Reviewed-by: Maceo Thompson <maceothompson@google.com>
1 parent 864243b commit 53a5385

File tree

3 files changed

+101
-6
lines changed

3 files changed

+101
-6
lines changed

internal/vulncheck/entries.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ import (
1010
"golang.org/x/tools/go/ssa"
1111
)
1212

13+
// entryPoints returns functions of topPackages considered entry
14+
// points of govulncheck analysis: main, inits, and exported methods
15+
// and functions.
16+
//
17+
// TODO(https://go.dev/issue/57221): currently, entry functions
18+
// that are generics are not considered an entry point.
1319
func entryPoints(topPackages []*ssa.Package) []*ssa.Function {
1420
var entries []*ssa.Function
1521
for _, pkg := range topPackages {

internal/vulncheck/utils.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
// the ssa program encapsulating the packages and top level
2929
// ssa packages corresponding to pkgs.
3030
func buildSSA(pkgs []*packages.Package, fset *token.FileSet) (*ssa.Program, []*ssa.Package) {
31-
// TODO(https://go.dev/issue/57221): what about entry functions that are generics?
3231
prog := ssa.NewProgram(fset, ssa.InstantiateGenerics)
3332

3433
imports := make(map[*packages.Package]*ssa.Package)
@@ -112,15 +111,17 @@ func dbTypeFormat(t types.Type) string {
112111

113112
// dbFuncName computes a function name consistent with the namings used in vulnerability
114113
// databases. Effectively, a qualified name of a function local to its enclosing package.
115-
// If a receiver is a pointer, this information is not encoded in the resulting name. The
116-
// name of anonymous functions is simply "". The function names are unique subject to the
117-
// enclosing package, but not globally.
114+
// If a receiver is a pointer, this information is not encoded in the resulting name. If
115+
// a function has type argument/parameter, this information is omitted. The name of
116+
// anonymous functions is simply "". The function names are unique subject to the enclosing
117+
// package, but not globally.
118118
//
119119
// Examples:
120120
//
121121
// func (a A) foo (...) {...} -> A.foo
122122
// func foo(...) {...} -> foo
123123
// func (b *B) bar (...) {...} -> B.bar
124+
// func (c C[T]) do(...) {...} -> C.do
124125
func dbFuncName(f *ssa.Function) string {
125126
selectBound := func(f *ssa.Function) types.Type {
126127
// If f is a "bound" function introduced by ssa for a given type, return the type.
@@ -153,9 +154,17 @@ func dbFuncName(f *ssa.Function) string {
153154
}
154155

155156
if qprefix == "" {
156-
return f.Name()
157+
return funcName(f)
157158
}
158-
return qprefix + "." + f.Name()
159+
return qprefix + "." + funcName(f)
160+
}
161+
162+
// funcName returns the name of the ssa function f.
163+
// It is f.Name() without additional type argument
164+
// information in case of generics.
165+
func funcName(f *ssa.Function) string {
166+
n, _, _ := strings.Cut(f.Name(), "[")
167+
return n
159168
}
160169

161170
// dbTypesFuncName is dbFuncName defined over *types.Func.

internal/vulncheck/utils_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
package vulncheck
66

77
import (
8+
"path"
89
"testing"
910

11+
"github.com/google/go-cmp/cmp"
12+
"golang.org/x/tools/go/packages/packagestest"
13+
"golang.org/x/tools/go/ssa/ssautil"
1014
"golang.org/x/vuln/internal/osv"
1115
)
1216

@@ -184,3 +188,79 @@ func TestFixedVersion(t *testing.T) {
184188
})
185189
}
186190
}
191+
192+
func TestDbSymbolName(t *testing.T) {
193+
e := packagestest.Export(t, packagestest.Modules, []packagestest.Module{
194+
{
195+
Name: "golang.org/package",
196+
Files: map[string]interface{}{
197+
"x/x.go": `
198+
package x
199+
200+
func Foo() {
201+
// needed for ssautil.Allfunctions
202+
x := a{}
203+
x.Do()
204+
x.NotDo()
205+
b := B[a]{}
206+
b.P()
207+
b.Q(x)
208+
Z[a]()
209+
}
210+
211+
func bar() {}
212+
213+
type a struct{}
214+
215+
func (x a) Do() {}
216+
func (x *a) NotDo() {
217+
}
218+
219+
type B[T any] struct{}
220+
221+
func (b *B[T]) P() {}
222+
func (b B[T]) Q(t T) {}
223+
224+
func Z[T any]() {}
225+
`},
226+
},
227+
})
228+
defer e.Cleanup()
229+
230+
graph := NewPackageGraph("go1.18")
231+
pkgs, err := graph.LoadPackages(e.Config, nil, []string{path.Join(e.Temp(), "package/x")})
232+
if err != nil {
233+
t.Fatal(err)
234+
}
235+
236+
want := map[string]bool{
237+
"init": true,
238+
"bar": true,
239+
"B.P": true,
240+
"B.Q": true,
241+
"a.Do": true,
242+
"a.NotDo": true,
243+
"Foo": true,
244+
"Z": true,
245+
}
246+
247+
// test dbFuncName
248+
prog, _ := buildSSA(pkgs, pkgs[0].Fset)
249+
got := make(map[string]bool)
250+
for f := range ssautil.AllFunctions(prog) {
251+
got[dbFuncName(f)] = true
252+
}
253+
if diff := cmp.Diff(want, got); diff != "" {
254+
t.Errorf("(-want;got+): %s", diff)
255+
}
256+
257+
// test dbTypesFuncName
258+
delete(want, "init") // init does not appear in types.Package
259+
got = make(map[string]bool)
260+
for _, s := range allSymbols(pkgs[0].Types) {
261+
got[s] = true
262+
}
263+
if diff := cmp.Diff(want, got); diff != "" {
264+
t.Errorf("(-want;got+): %s", diff)
265+
}
266+
}

0 commit comments

Comments
 (0)