cmd/go: explicitly reject module paths "go" and "toolchain"

The module paths "go" and "toolchain" are reserved for the dependency on
the go and toolchain versions. Check for those paths in go mod init to
create modules, go mod edit, and in the module loader and return an
error when attempting to use those paths for a work module. Trying to
init or load a work module with a go.mod that specifies the module path
"go" panics since Go 1.21 (when the toolchain switching logic and the
implicit dependencies on the "go" module was introduced), and this
change returns a proper error instead of panicking.

Fixes #74784

Change-Id: I10e712f8fddbea63edaeb37e14c6d783722e623f
Reviewed-on: https://go-review.googlesource.com/c/go/+/691515
Reviewed-by: Ian Alexander <jitsu@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Matloob <matloob@google.com>
This commit is contained in:
Michael Matloob 2025-07-29 14:17:33 -04:00
parent a4d99770c0
commit c0ee2fd4e3
4 changed files with 45 additions and 1 deletions

View file

@ -234,7 +234,11 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) {
}
if *editModule != "" {
if err := module.CheckImportPath(*editModule); err != nil {
err := module.CheckImportPath(*editModule)
if err == nil {
err = modload.CheckReservedModulePath(*editModule)
}
if err != nil {
base.Fatalf("go: invalid -module: %v", err)
}
}

View file

@ -1122,6 +1122,16 @@ func errWorkTooOld(gomod string, wf *modfile.WorkFile, goVers string) error {
base.ShortPath(filepath.Dir(gomod)), goVers, verb, gover.FromGoWork(wf))
}
// CheckReservedModulePath checks whether the module path is a reserved module path
// that can't be used for a user's module.
func CheckReservedModulePath(path string) error {
if gover.IsToolchain(path) {
return errors.New("module path is reserved")
}
return nil
}
// CreateModFile initializes a new module by creating a go.mod file.
//
// If modPath is empty, CreateModFile will attempt to infer the path from the
@ -1156,6 +1166,8 @@ func CreateModFile(ctx context.Context, modPath string) {
}
}
base.Fatal(err)
} else if err := CheckReservedModulePath(modPath); err != nil {
base.Fatalf(`go: invalid module path %q: `, modPath)
} else if _, _, ok := module.SplitPathVersion(modPath); !ok {
if strings.HasPrefix(modPath, "gopkg.in/") {
invalidMajorVersionMsg := fmt.Errorf("module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN:\n\tgo mod init %s", suggestGopkgIn(modPath))

View file

@ -68,6 +68,8 @@ func ReadModFile(gomod string, fix modfile.VersionFixer) (data []byte, f *modfil
if f.Module == nil {
// No module declaration. Must add module path.
return nil, nil, fmt.Errorf("error reading %s: missing module declaration. To specify the module path:\n\tgo mod edit -module=example.com/mod", base.ShortPath(gomod))
} else if err := CheckReservedModulePath(f.Module.Mod.Path); err != nil {
return nil, nil, fmt.Errorf("error reading %s: invalid module path: %q", base.ShortPath(gomod), f.Module.Mod.Path)
}
return data, f, err

View file

@ -0,0 +1,26 @@
# Don't allow the creation of modules with special "go" or "toolchain" paths.
! go mod init go
! stderr 'panic'
stderr 'invalid module path'
! go mod init toolchain
! stderr 'panic'
stderr 'invalid module path'
# A module that contains the path element "go" is okay.
go mod init example.com/go
stderr 'creating new go.mod'
# go mod edit won't allow a reserved module path either
! go mod edit -module=go
stderr 'invalid -module'
# The go command should check for work modules for bad
# names to return a proper error and avoid a panic.
cp badmod.txt go.mod
! go list
! stderr panic
stderr 'invalid module path'
-- badmod.txt --
module go