imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package containing "rand.Read" was "crypto/rand". goimports was updated to know that, and zstdlib.go contains a note that it's ambiguous: "rand.Perm": "math/rand", "rand.Prime": "crypto/rand", "rand.Rand": "math/rand", // "rand.Read" is ambiguous "rand.Reader": "crypto/rand", "rand.Seed": "math/rand", "rand.Source": "math/rand", The intention originally was that such ambiguous things would never be resolved, even randomly. But a later change added support for build.Default.SrcDirs, which meant GOROOT was also searched for ambiguous things. Or maybe I forget the history. In any case, when goimports tried to resolve "rand.Read", the findImportStdlib check was returning nothing, which lead to the $GOROOT being searched, where math/rand was picked by chance. That's a dangerous default when the intentional might've been crypto/rand. Special case it and prefer crypto/rand if there's no more specific clue either way. Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c Reviewed-on: https://go-review.googlesource.com/24847 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Andrew Gerrand <adg@golang.org>
This commit is contained in:
parent
cda5280914
commit
0835c73534
|
@ -369,6 +369,16 @@ func findImportGoPath(pkgName string, symbols map[string]bool, filename string)
|
||||||
if pkg, rename, ok := findImportStdlib(pkgName, symbols); ok {
|
if pkg, rename, ok := findImportStdlib(pkgName, symbols); ok {
|
||||||
return pkg, rename, nil
|
return pkg, rename, nil
|
||||||
}
|
}
|
||||||
|
if pkgName == "rand" && symbols["Read"] {
|
||||||
|
// Special-case rand.Read.
|
||||||
|
//
|
||||||
|
// If findImportStdlib didn't find it above, don't go
|
||||||
|
// searching for it, lest it find and pick math/rand
|
||||||
|
// in GOROOT (new as of Go 1.6)
|
||||||
|
//
|
||||||
|
// crypto/rand is the safer choice.
|
||||||
|
return "", false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(sameer): look at the import lines for other Go files in the
|
// TODO(sameer): look at the import lines for other Go files in the
|
||||||
// local directory, since the user is likely to import the same packages
|
// local directory, since the user is likely to import the same packages
|
||||||
|
@ -459,8 +469,12 @@ func (fn visitFn) Visit(node ast.Node) ast.Visitor {
|
||||||
|
|
||||||
func findImportStdlib(shortPkg string, symbols map[string]bool) (importPath string, rename, ok bool) {
|
func findImportStdlib(shortPkg string, symbols map[string]bool) (importPath string, rename, ok bool) {
|
||||||
for symbol := range symbols {
|
for symbol := range symbols {
|
||||||
path := stdlib[shortPkg+"."+symbol]
|
key := shortPkg + "." + symbol
|
||||||
|
path := stdlib[key]
|
||||||
if path == "" {
|
if path == "" {
|
||||||
|
if key == "rand.Read" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
return "", false, false
|
return "", false, false
|
||||||
}
|
}
|
||||||
if importPath != "" && importPath != path {
|
if importPath != "" && importPath != path {
|
||||||
|
@ -469,5 +483,8 @@ func findImportStdlib(shortPkg string, symbols map[string]bool) (importPath stri
|
||||||
}
|
}
|
||||||
importPath = path
|
importPath = path
|
||||||
}
|
}
|
||||||
|
if importPath == "" && shortPkg == "rand" && symbols["Read"] {
|
||||||
|
return "crypto/rand", false, true
|
||||||
|
}
|
||||||
return importPath, false, importPath != ""
|
return importPath, false, importPath != ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -1008,14 +1008,18 @@ type Buffer2 struct {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindImportInternal(t *testing.T) {
|
func withEmptyGoPath(fn func()) {
|
||||||
pkgIndexOnce = &sync.Once{}
|
pkgIndexOnce = &sync.Once{}
|
||||||
oldGOPATH := build.Default.GOPATH
|
oldGOPATH := build.Default.GOPATH
|
||||||
build.Default.GOPATH = ""
|
build.Default.GOPATH = ""
|
||||||
defer func() {
|
defer func() {
|
||||||
build.Default.GOPATH = oldGOPATH
|
build.Default.GOPATH = oldGOPATH
|
||||||
}()
|
}()
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindImportInternal(t *testing.T) {
|
||||||
|
withEmptyGoPath(func() {
|
||||||
// Check for src/internal/race, not just src/internal,
|
// Check for src/internal/race, not just src/internal,
|
||||||
// so that we can run this test also against go1.5
|
// so that we can run this test also against go1.5
|
||||||
// (which doesn't contain that file).
|
// (which doesn't contain that file).
|
||||||
|
@ -1040,6 +1044,49 @@ func TestFindImportInternal(t *testing.T) {
|
||||||
if got != "" || rename {
|
if got != "" || rename {
|
||||||
t.Errorf(`findImportGoPath("race", Acquire ...)=%q, %t, want "", false`, got, rename)
|
t.Errorf(`findImportGoPath("race", Acquire ...)=%q, %t, want "", false`, got, rename)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// rand.Read should prefer crypto/rand.Read, not math/rand.Read.
|
||||||
|
func TestFindImportRandRead(t *testing.T) {
|
||||||
|
withEmptyGoPath(func() {
|
||||||
|
file := filepath.Join(runtime.GOROOT(), "src/foo/x.go") // dummy
|
||||||
|
tests := []struct {
|
||||||
|
syms []string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
syms: []string{"Read"},
|
||||||
|
want: "crypto/rand",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
syms: []string{"Read", "NewZipf"},
|
||||||
|
want: "math/rand",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
syms: []string{"NewZipf"},
|
||||||
|
want: "math/rand",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
syms: []string{"Read", "Prime"},
|
||||||
|
want: "crypto/rand",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
m := map[string]bool{}
|
||||||
|
for _, sym := range tt.syms {
|
||||||
|
m[sym] = true
|
||||||
|
}
|
||||||
|
got, _, err := findImportGoPath("rand", m, file)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("for %q: %v", tt.syms, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("for %q, findImportGoPath = %q; want %q", tt.syms, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindImportVendor(t *testing.T) {
|
func TestFindImportVendor(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue