cmd/go: prevent panic in go work use

Check if paths passed as arguments are existing directories.

Fixes #51841
Fixes #51749

Change-Id: Icfd148627e6f2c4651d6f923a37d413e68c67f6c
GitHub-Last-Rev: 77fffa7635
GitHub-Pull-Request: golang/go#51845
Reviewed-on: https://go-review.googlesource.com/c/go/+/394154
Trust: Bryan Mills <bcmills@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Trust: Emmanuel Odeke <emmanuel@orijtech.com>
Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Filippo Rossi 2022-04-04 06:25:32 +00:00 committed by Emmanuel Odeke
parent 884e75fa53
commit 492c85ab84
3 changed files with 38 additions and 22 deletions

View File

@ -12,7 +12,6 @@ import (
"cmd/go/internal/modload"
"cmd/go/internal/str"
"context"
"errors"
"fmt"
"io/fs"
"os"
@ -109,17 +108,33 @@ func runUse(ctx context.Context, cmd *base.Command, args []string) {
base.Fatalf("go: 'go work use' requires one or more directory arguments")
}
for _, useDir := range args {
if !*useR {
if target, err := fsys.Stat(useDir); err == nil && !target.IsDir() {
base.Errorf(`go: argument "%s" is not a directory`, useDir)
absArg, _ := pathRel(workDir, useDir)
info, err := fsys.Stat(absArg)
if err != nil {
// Errors raised from os.Stat are formatted to be more user-friendly.
if os.IsNotExist(err) {
base.Errorf("go: directory %v does not exist", absArg)
} else {
lookDir(useDir)
base.Errorf("go: %v", err)
}
continue
} else if !info.IsDir() {
base.Errorf("go: %s is not a directory", absArg)
continue
}
if !*useR {
lookDir(useDir)
continue
}
// Add or remove entries for any subdirectories that still exist.
err := fsys.Walk(useDir, func(path string, info fs.FileInfo, err error) error {
fsys.Walk(useDir, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
if info.Mode()&fs.ModeSymlink != 0 {
if target, err := fsys.Stat(path); err == nil && target.IsDir() {
@ -131,13 +146,9 @@ func runUse(ctx context.Context, cmd *base.Command, args []string) {
lookDir(path)
return nil
})
if err != nil && !errors.Is(err, os.ErrNotExist) {
base.Errorf("go: %v", err)
}
// Remove entries for subdirectories that no longer exist.
// Because they don't exist, they will be skipped by Walk.
absArg, _ := pathRel(workDir, useDir)
for absDir, _ := range haveDirs {
if str.HasFilePathPrefix(absDir, absArg) {
if _, ok := keepDirs[absDir]; !ok {

View File

@ -1,12 +0,0 @@
cp go.work go.work.orig
# If an argument to 'go work use' is a file it should be handled gracefully as
# an error and go.work should not be modified
! go work use foo.txt
stderr '^go: argument "foo\.txt" is not a directory$'
cmp go.work go.work.orig
-- go.work --
go 1.18
-- foo.txt --

View File

@ -0,0 +1,17 @@
! go work use foo bar baz
stderr '^go: '$WORK'[/\\]gopath[/\\]src[/\\]foo is not a directory'
stderr '^go: directory '$WORK'[/\\]gopath[/\\]src[/\\]baz does not exist'
cmp go.work go.work_want
! go work use -r qux
stderr '^go: '$WORK'[/\\]gopath[/\\]src[/\\]qux is not a directory'
-- go.work --
go 1.18
-- go.work_want --
go 1.18
-- foo --
-- qux --
-- bar/go.mod --
module bar