Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/vuln: govulncheck reports "undeclared name" for global variable declared in _test.go file #55016

Closed
derat opened this issue Sep 12, 2022 · 6 comments
Labels
FrozenDueToAge Unfortunate vulncheck or vulndb Issues for the x/vuln or x/vulndb repo
Milestone

Comments

@derat
Copy link

derat commented Sep 12, 2022

What version of Go are you using (go version)?

$ go version
go version go1.19 linux/amd64

Does this issue reproduce at the latest version of golang.org/x/vuln?

Yes (I ran go install golang.org/x/vuln/cmd/govulncheck@latest a few minutes ago).

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
...
GOARCH="amd64"
...
GOHOSTARCH="amd64"
GOHOSTOS="linux"
...

What did you do?

I ran govulncheck ./... on a more-complicated version of the code in https://github.com/derat/bugs/tree/main/golang/govulncheck-global-in-test-file.

What did you expect to see?

I expected govulncheck to run successfully and maybe print some vulnerabilities.

What did you see instead?

govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.

Scanning for dependencies with known vulnerabilities...
govulncheck: Packages contain errors:
.../test/lib.go:4:36: undeclared name: bar

A function in test/lib.go references a global variable declared in test/foo_test.go. The function is only called by foo_test.go.

In the real-life scenario where I saw this, the test package contains tests that exercise code across a multi-language project. foo_test.go contains the actual tests and initializes global variables needed for testing, while lib.go and other files contain helper functions that are called by foo_test.go and that reference the global variables.

I'm aware that this setup is strange (or wrong?), so this might be working as intended:

  • Probably the helper files should be named e.g. lib_test.go; the shorter names were used to make it clear that they don't contain the actual tests.
  • Perhaps the global variables should be declared in a non-_test-suffixed file.

I'm just filing an issue since go vet seems to be able to handle this scenario without printing an undeclared name error:

% go vet ./...
%
@derat derat added the vulncheck or vulndb Issues for the x/vuln or x/vulndb repo label Sep 12, 2022
@gopherbot gopherbot added this to the Unreleased milestone Sep 12, 2022
@julieqiu julieqiu modified the milestones: Unreleased, vuln/2022 Sep 12, 2022
@julieqiu julieqiu removed the x/vuln label Sep 12, 2022
@timothy-king
Copy link
Contributor

govulncheck is failing due to a type checking problem while loading.

What you are describing should be a type checking error for compiling the package test when compiling outside of go test. Say go build yourmod.com/dir/test should fail. You may want to take a look at https://pkg.go.dev/cmd/go#hdr-Test_packages .

'Go test' recompiles each package along with any files with names matching the file pattern "*test.go". These additional files can contain test functions, benchmark functions, fuzz tests and example functions. See 'go help testfunc' for more. Each listed package causes the execution of a separate test binary. Files whose names begin with "" (including "_test.go") or "." are ignored.

Test files that declare a package with the suffix "_test" will be compiled as a separate package, and then linked and run with the main test binary.

There are actually up to 4 ways a directory can define Go packages once you take into account testing and binaries. Your definitions appear to be split over 2 of these. If the test package is a testing utility package that only used from go test, you might be avoiding seeing this as as a problem.

go vet ./... not complaining is a bit surprising to me. I am guessing that the go command is sending a different list of .go files than I would expect. Speculating though. Can you give a minimal reproducer? File contents + directory structure would help here.

My general advice for you though (that does not improve govulncheck) is to make sure test makes sense as a package on its own.

@derat
Copy link
Author

derat commented Sep 12, 2022

Thanks for the quick reply! The test package is never compiled outside of go test, which is why this hadn't caused problems, but yes, I was surprised that the results were different between go vet and govulncheck.

Can you give a minimal reproducer? File contents + directory structure would help here.

Are you able to repro the error using the repo/directory in the initial report (https://github.com/derat/bugs/tree/main/golang/govulncheck-global-in-test-file)?

% govulncheck ./...                 
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.

Scanning for dependencies with known vulnerabilities...
govulncheck: Packages contain errors:
.../bugs/golang/govulncheck-global-in-test-file/test/lib.go:4:36: undeclared name: bar
% go vet ./...
%

If I add an additional reference to a variable that isn't declared anywhere, then go vet also fails:

% go vet ./...  
# github.com/derat/bugs/golang/govulncheck-globals/test
vet: test/lib.go:4:29: undeclared name: baz

@toothrot toothrot added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Sep 13, 2022
@timothy-king
Copy link
Contributor

Are you able to repro the error using the repo/directory in the initial report (https://github.com/derat/bugs/tree/main/golang/govulncheck-global-in-test-file)?

I was. Apologies for the reading comprehension issues on my side.

For reference for others here are the relevant files.

--- test/foo_test.foo ---
package test

import "testing"

var bar = "bar"

func TestFoo(t *testing.T) { doSomething() }

--- test/lib.go ---
package test

// govulncheck fails on the next line with "undeclared name: bar"
func doSomething() string { return bar }

--- main.go ---
package main

func main() {}

On this go vet -x ./... only shows one action being taken on this snippet:

	"GoFiles": [
		"/Users/taking/tmp/i55016/bugs/golang/govulncheck-global-in-test-file/test/lib.go",
		"/Users/taking/tmp/i55016/bugs/golang/govulncheck-global-in-test-file/test/foo_test.go"
	],

If this is the only action it is not surprising that go vet is silent.

Right now govulncheck is run with packages.Config.Tests == *testFlag (false by default). This effectively treats this as only having test/lib.go. I confirmed we are only loading one x/tools/go/packages.Package for test with this config. This will not type check.

If we turn packages.Config.Tests on we will inspect the package as both [test/lib.go] and [test/lib.go, test/foo_test.go]. The first of these will crash.

The code in question is being written in a way that it does not typecheck under all usages by not considering all of the ways a test package can be loaded (See https://pkg.go.dev/cmd/go#hdr-Test_packages). The simplest solution for users is to write code that conforms to all of the ways a package can be loaded. (In this case, the test package should either always use "_test.go" or do not mix ".go" with "_test.go" for the same conceptual package.)

go vet is being appropriately generous on code that does not type check. govulncheck should print an error on [test/lib.go]. It not printing an error and silently suppressing diagnostics would not helpful.

I am somewhat tempted to just consider this as "Unfortunate" and close. The only candidate alternative I can see is to change go/packages so that it can load [test/lib.go, test/foo_test.go] to match go vet ./....

@derat
Copy link
Author

derat commented Sep 27, 2022

Thanks for the investigation! For whatever it's worth, I'm glad that govulncheck printed an error here since it got me to fix some weird code.

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/436835 mentions this issue: go/analysis: add note about package loading.

@timothy-king
Copy link
Contributor

timothy-king commented Sep 29, 2022

I am going to close as Unfortunate for now. We will keep an eye out for this impacting others. If this is impacting you too, please let us know.

I'll try to add some internal documentation about what is going on in the meantime.

@timothy-king timothy-king closed this as not planned Won't fix, can't repro, duplicate, stale Sep 29, 2022
@timothy-king timothy-king added Unfortunate and removed NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Sep 29, 2022
@golang golang locked and limited conversation to collaborators Sep 29, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge Unfortunate vulncheck or vulndb Issues for the x/vuln or x/vulndb repo
Projects
None yet
Development

No branches or pull requests

5 participants