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

cmd/go: hangs with 100% CPU on import of absolute path in the presence of go.mod #27558

Closed
bmeh opened this issue Sep 7, 2018 · 7 comments
Closed
Labels
FrozenDueToAge modules NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@bmeh
Copy link

bmeh commented Sep 7, 2018

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

go version go1.11 linux/amd64

Does this issue reproduce with the latest release?

Yes.

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

GOARCH="amd64"
GOBIN=""
GOCACHE="/home/bmeh/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/bmeh/go"
GOPROXY=""
GORACE=""
GOROOT="/home/bmeh/.local/pkg/go-1.11"
GOTMPDIR=""
GOTOOLDIR="/home/bmeh/.local/pkg/go-1.11/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build720301179=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I tried to execute go build main.go, where main.go imports an absolute path ("/home/bmeh/foo/logger").

If file go.mod does not exist, it prints:
main.go:4:8: import "/home/bmeh/foo/logger": cannot import absolute path
Whereas if I create go.mod via go mod init main (which doesn't make logger a dependency, should it? In my opinion, it should, or perhaps in the future versions.), it hangs indefinitely, consuming 100% CPU. If I use ./logger as the import path, it doesn't hang, it prints build main: cannot find module for path _/home/bmeh/foo/logger instead, even though go.mod exists in logger/ and is properly vendored[1] via go mod vendor, but I guess that's not how you handle internal libraries anyway, just merely pointing out the inconsistency.

It is worth mentioning that go build main.go succeeds in case there is no go.mod and the import path is ./logger, all while being outside of $GOPATH, but of course it checks for the dependencies in $GOPATH. I am not even sure how to make a vendored version of main.go that makes logger/* (which is an internal library) a dependency, along with its own vendored dependencies.[2]

Additionally, in case the import path in main.go is an absolute path ("/home/bmeh/foo/logger"), go mod vendor hangs indefinitely as well, but if it's a relative path ("./logger"), it says: go: no dependencies to vendor

To sum up: both go build, and go mod vendor hangs in case an absolute path is imported AND go.mod is present, if go.mod doesn't exist, it prints an error and exits. It works when go.mod doesn't exist, and the import path is a relative path.

[1] Further explanation needed as to why that's the case, or if there are any plans to change this behavior in future releases. Additionally, in my opinion, the error message is cryptic, and why does it append _ in front of it when I am clearly importing /home/bmeh/foo/logger?

[2] Perhaps anyone could help me out with that?

Directory tree:

/home/bmeh/foo
.
├── logger
│   ├── go.mod
│   ├── go.sum
│   ├── logger.go
│   └── vendor
│       ├── github.com
│       │   ├── mattn
│       │   │   ├── go-colorable
│       │   │   │   ├── colorable_appengine.go
│       │   │   │   ├── colorable_others.go
│       │   │   │   ├── colorable_windows.go
│       │   │   │   ├── LICENSE
│       │   │   │   ├── noncolorable.go
│       │   │   │   └── README.md
│       │   │   └── go-isatty
│       │   │       ├── doc.go
│       │   │       ├── isatty_appengine.go
│       │   │       ├── isatty_bsd.go
│       │   │       ├── isatty_linux.go
│       │   │       ├── isatty_linux_ppc64x.go
│       │   │       ├── isatty_others.go
│       │   │       ├── isatty_solaris.go
│       │   │       ├── isatty_windows.go
│       │   │       ├── LICENSE
│       │   │       └── README.md
│       │   └── mgutz
│       │       └── ansi
│       │           ├── ansi.go
│       │           ├── doc.go
│       │           ├── LICENSE
│       │           ├── print.go
│       │           └── README.md
│       ├── golang.org
│       │   └── x
│       │       └── sys
│       │           ├── AUTHORS
│       │           ├── CONTRIBUTORS
│       │           ├── LICENSE
│       │           ├── PATENTS
│       │           └── unix
│       │               ├── affinity_linux.go
│       │               ├── aliases.go
│       │               ├── asm_darwin_386.s
│       │               ├── asm_darwin_amd64.s
│       │               ├── asm_darwin_arm64.s
│       │               ├── asm_darwin_arm.s
│       │               ├── asm_dragonfly_amd64.s
│       │               ├── asm_freebsd_386.s
│       │               ├── asm_freebsd_amd64.s
│       │               ├── asm_freebsd_arm.s
│       │               ├── asm_linux_386.s
│       │               ├── asm_linux_amd64.s
│       │               ├── asm_linux_arm64.s
│       │               ├── asm_linux_arm.s
│       │               ├── asm_linux_mips64x.s
│       │               ├── asm_linux_mipsx.s
│       │               ├── asm_linux_ppc64x.s
│       │               ├── asm_linux_s390x.s
│       │               ├── asm_netbsd_386.s
│       │               ├── asm_netbsd_amd64.s
│       │               ├── asm_netbsd_arm.s
│       │               ├── asm_openbsd_386.s
│       │               ├── asm_openbsd_amd64.s
│       │               ├── asm_openbsd_arm.s
│       │               ├── asm_solaris_amd64.s
│       │               ├── bluetooth_linux.go
│       │               ├── cap_freebsd.go
│       │               ├── constants.go
│       │               ├── dev_aix_ppc64.go
│       │               ├── dev_aix_ppc.go
│       │               ├── dev_darwin.go
│       │               ├── dev_dragonfly.go
│       │               ├── dev_freebsd.go
│       │               ├── dev_linux.go
│       │               ├── dev_netbsd.go
│       │               ├── dev_openbsd.go
│       │               ├── dirent.go
│       │               ├── endian_big.go
│       │               ├── endian_little.go
│       │               ├── env_unix.go
│       │               ├── errors_freebsd_386.go
│       │               ├── errors_freebsd_amd64.go
│       │               ├── errors_freebsd_arm.go
│       │               ├── fcntl.go
│       │               ├── fcntl_linux_32bit.go
│       │               ├── gccgo_c.c
│       │               ├── gccgo.go
│       │               ├── gccgo_linux_amd64.go
│       │               ├── ioctl.go
│       │               ├── mkall.sh
│       │               ├── mkerrors.sh
│       │               ├── mkpost.go
│       │               ├── mksyscall_aix.pl
│       │               ├── mksyscall.pl
│       │               ├── mksyscall_solaris.pl
│       │               ├── mksysctl_openbsd.pl
│       │               ├── mksysnum_darwin.pl
│       │               ├── mksysnum_dragonfly.pl
│       │               ├── mksysnum_freebsd.pl
│       │               ├── mksysnum_netbsd.pl
│       │               ├── mksysnum_openbsd.pl
│       │               ├── openbsd_pledge.go
│       │               ├── pagesize_unix.go
│       │               ├── race0.go
│       │               ├── race.go
│       │               ├── README.md
│       │               ├── sockcmsg_linux.go
│       │               ├── sockcmsg_unix.go
│       │               ├── str.go
│       │               ├── syscall_aix.go
│       │               ├── syscall_aix_ppc64.go
│       │               ├── syscall_aix_ppc.go
│       │               ├── syscall_bsd.go
│       │               ├── syscall_darwin_386.go
│       │               ├── syscall_darwin_amd64.go
│       │               ├── syscall_darwin_arm64.go
│       │               ├── syscall_darwin_arm.go
│       │               ├── syscall_darwin.go
│       │               ├── syscall_dragonfly_amd64.go
│       │               ├── syscall_dragonfly.go
│       │               ├── syscall_freebsd_386.go
│       │               ├── syscall_freebsd_amd64.go
│       │               ├── syscall_freebsd_arm.go
│       │               ├── syscall_freebsd.go
│       │               ├── syscall.go
│       │               ├── syscall_linux_386.go
│       │               ├── syscall_linux_amd64_gc.go
│       │               ├── syscall_linux_amd64.go
│       │               ├── syscall_linux_arm64.go
│       │               ├── syscall_linux_arm.go
│       │               ├── syscall_linux_gc_386.go
│       │               ├── syscall_linux_gccgo_386.go
│       │               ├── syscall_linux_gccgo_arm.go
│       │               ├── syscall_linux_gc.go
│       │               ├── syscall_linux.go
│       │               ├── syscall_linux_mips64x.go
│       │               ├── syscall_linux_mipsx.go
│       │               ├── syscall_linux_ppc64x.go
│       │               ├── syscall_linux_s390x.go
│       │               ├── syscall_linux_sparc64.go
│       │               ├── syscall_netbsd_386.go
│       │               ├── syscall_netbsd_amd64.go
│       │               ├── syscall_netbsd_arm.go
│       │               ├── syscall_netbsd.go
│       │               ├── syscall_openbsd_386.go
│       │               ├── syscall_openbsd_amd64.go
│       │               ├── syscall_openbsd_arm.go
│       │               ├── syscall_openbsd.go
│       │               ├── syscall_solaris_amd64.go
│       │               ├── syscall_solaris.go
│       │               ├── syscall_unix_gc.go
│       │               ├── syscall_unix.go
│       │               ├── timestruct.go
│       │               ├── types_aix.go
│       │               ├── types_darwin.go
│       │               ├── types_dragonfly.go
│       │               ├── types_freebsd.go
│       │               ├── types_netbsd.go
│       │               ├── types_openbsd.go
│       │               ├── types_solaris.go
│       │               ├── xattr_bsd.go
│       │               ├── zerrors_aix_ppc64.go
│       │               ├── zerrors_aix_ppc.go
│       │               ├── zerrors_darwin_386.go
│       │               ├── zerrors_darwin_amd64.go
│       │               ├── zerrors_darwin_arm64.go
│       │               ├── zerrors_darwin_arm.go
│       │               ├── zerrors_dragonfly_amd64.go
│       │               ├── zerrors_freebsd_386.go
│       │               ├── zerrors_freebsd_amd64.go
│       │               ├── zerrors_freebsd_arm.go
│       │               ├── zerrors_linux_386.go
│       │               ├── zerrors_linux_amd64.go
│       │               ├── zerrors_linux_arm64.go
│       │               ├── zerrors_linux_arm.go
│       │               ├── zerrors_linux_mips64.go
│       │               ├── zerrors_linux_mips64le.go
│       │               ├── zerrors_linux_mips.go
│       │               ├── zerrors_linux_mipsle.go
│       │               ├── zerrors_linux_ppc64.go
│       │               ├── zerrors_linux_ppc64le.go
│       │               ├── zerrors_linux_s390x.go
│       │               ├── zerrors_linux_sparc64.go
│       │               ├── zerrors_netbsd_386.go
│       │               ├── zerrors_netbsd_amd64.go
│       │               ├── zerrors_netbsd_arm.go
│       │               ├── zerrors_openbsd_386.go
│       │               ├── zerrors_openbsd_amd64.go
│       │               ├── zerrors_openbsd_arm.go
│       │               ├── zerrors_solaris_amd64.go
│       │               ├── zptrace386_linux.go
│       │               ├── zptracearm_linux.go
│       │               ├── zptracemipsle_linux.go
│       │               ├── zptracemips_linux.go
│       │               ├── zsyscall_aix_ppc64.go
│       │               ├── zsyscall_aix_ppc.go
│       │               ├── zsyscall_darwin_386.go
│       │               ├── zsyscall_darwin_amd64.go
│       │               ├── zsyscall_darwin_arm64.go
│       │               ├── zsyscall_darwin_arm.go
│       │               ├── zsyscall_dragonfly_amd64.go
│       │               ├── zsyscall_freebsd_386.go
│       │               ├── zsyscall_freebsd_amd64.go
│       │               ├── zsyscall_freebsd_arm.go
│       │               ├── zsyscall_linux_386.go
│       │               ├── zsyscall_linux_amd64.go
│       │               ├── zsyscall_linux_arm64.go
│       │               ├── zsyscall_linux_arm.go
│       │               ├── zsyscall_linux_mips64.go
│       │               ├── zsyscall_linux_mips64le.go
│       │               ├── zsyscall_linux_mips.go
│       │               ├── zsyscall_linux_mipsle.go
│       │               ├── zsyscall_linux_ppc64.go
│       │               ├── zsyscall_linux_ppc64le.go
│       │               ├── zsyscall_linux_s390x.go
│       │               ├── zsyscall_linux_sparc64.go
│       │               ├── zsyscall_netbsd_386.go
│       │               ├── zsyscall_netbsd_amd64.go
│       │               ├── zsyscall_netbsd_arm.go
│       │               ├── zsyscall_openbsd_386.go
│       │               ├── zsyscall_openbsd_amd64.go
│       │               ├── zsyscall_openbsd_arm.go
│       │               ├── zsyscall_solaris_amd64.go
│       │               ├── zsysctl_openbsd_386.go
│       │               ├── zsysctl_openbsd_amd64.go
│       │               ├── zsysctl_openbsd_arm.go
│       │               ├── zsysnum_darwin_386.go
│       │               ├── zsysnum_darwin_amd64.go
│       │               ├── zsysnum_darwin_arm64.go
│       │               ├── zsysnum_darwin_arm.go
│       │               ├── zsysnum_dragonfly_amd64.go
│       │               ├── zsysnum_freebsd_386.go
│       │               ├── zsysnum_freebsd_amd64.go
│       │               ├── zsysnum_freebsd_arm.go
│       │               ├── zsysnum_linux_386.go
│       │               ├── zsysnum_linux_amd64.go
│       │               ├── zsysnum_linux_arm64.go
│       │               ├── zsysnum_linux_arm.go
│       │               ├── zsysnum_linux_mips64.go
│       │               ├── zsysnum_linux_mips64le.go
│       │               ├── zsysnum_linux_mips.go
│       │               ├── zsysnum_linux_mipsle.go
│       │               ├── zsysnum_linux_ppc64.go
│       │               ├── zsysnum_linux_ppc64le.go
│       │               ├── zsysnum_linux_s390x.go
│       │               ├── zsysnum_linux_sparc64.go
│       │               ├── zsysnum_netbsd_386.go
│       │               ├── zsysnum_netbsd_amd64.go
│       │               ├── zsysnum_netbsd_arm.go
│       │               ├── zsysnum_openbsd_386.go
│       │               ├── zsysnum_openbsd_amd64.go
│       │               ├── zsysnum_openbsd_arm.go
│       │               ├── ztypes_aix_ppc64.go
│       │               ├── ztypes_aix_ppc.go
│       │               ├── ztypes_darwin_386.go
│       │               ├── ztypes_darwin_amd64.go
│       │               ├── ztypes_darwin_arm64.go
│       │               ├── ztypes_darwin_arm.go
│       │               ├── ztypes_dragonfly_amd64.go
│       │               ├── ztypes_freebsd_386.go
│       │               ├── ztypes_freebsd_amd64.go
│       │               ├── ztypes_freebsd_arm.go
│       │               ├── ztypes_linux_386.go
│       │               ├── ztypes_linux_amd64.go
│       │               ├── ztypes_linux_arm64.go
│       │               ├── ztypes_linux_arm.go
│       │               ├── ztypes_linux_mips64.go
│       │               ├── ztypes_linux_mips64le.go
│       │               ├── ztypes_linux_mips.go
│       │               ├── ztypes_linux_mipsle.go
│       │               ├── ztypes_linux_ppc64.go
│       │               ├── ztypes_linux_ppc64le.go
│       │               ├── ztypes_linux_s390x.go
│       │               ├── ztypes_linux_sparc64.go
│       │               ├── ztypes_netbsd_386.go
│       │               ├── ztypes_netbsd_amd64.go
│       │               ├── ztypes_netbsd_arm.go
│       │               ├── ztypes_openbsd_386.go
│       │               ├── ztypes_openbsd_amd64.go
│       │               ├── ztypes_openbsd_arm.go
│       │               └── ztypes_solaris_amd64.go
│       └── modules.txt
└── main.go

12 directories, 271 files

What did you expect to see?

Gracefully exit with a descriptive error message.

What did you see instead?

It hung indefinitely with 100% CPU usage.


@myitcv

@bmeh
Copy link
Author

bmeh commented Sep 7, 2018

@gopherbot modules

@bmeh
Copy link
Author

bmeh commented Sep 7, 2018

Strace output can be found here: https://ptpb.pw/APnwN53-Q0MgIUSmM43aOVsPAxlq

@bmeh
Copy link
Author

bmeh commented Sep 10, 2018

More information, an easy way to reproduce:

$ GOPATH=/tmp
$ mkdir /tmp/foo && cd /tmp/foo
Create main.go here with the contents below
$ go mod init foo (or anything besides `foo`, does not seem to matter)
$ go build main.go <- hangs
$ go mod vendor <- hangs

main.go:

package main

import "/tmp/foo/bar"

func main() {
}

Notes:

  1. In this case the absolute import path does not need to exist, it hangs regardless. Feel free to play around with it. If you are unable to reproduce it following those steps, please let me know and I will dig deeper.
  2. The work directory is empty.
  3. The directory structure does not seem to matter either.

@myitcv
Copy link
Member

myitcv commented Sep 10, 2018

As I mentioned over in #27474 (comment):

Relative import paths will not work. They might work with go run but with GOPATH/modules mode they will not work at all.

Using an absolute path for an import path is also undefined (although I agree it should fail more gracefully than simply hanging). I will retitle the issue for this bug.

Hence this issue only exists to tidy up a very uncommon edge case where someone has, by accident, used an absolute import path and the experience should be better than simply hanging.

@bmeh
Copy link
Author

bmeh commented Sep 10, 2018

Just to clarify, relative import paths do work as long as the go.mod file does not exist, i.e. as you have said: with modules they will not work, although the GOPATH part seems inaccurate as I am able to run go build main.go (which imports a relative path) and succeed in both cases: inside and outside $GOPATH.

In the presence of go.mod:

  • relative import path: build .: cannot find module for path _/tmp/foo/bar
  • absolute import path: this issue

In the lack of presence of go.mod:

  • relative import path: compiles and works
  • absolute import path: main.go:4:2: import "/tmp/foo/bar": cannot import absolute path

And yes, that is exactly my answer to the question "What did you expect to see?". :P

@myitcv
Copy link
Member

myitcv commented Sep 11, 2018

@bmeh

relative import paths do work as long as the go.mod file does not exist

I note #20883, in particular #20883 (comment). Whilst relative imports might work in some situations outside of GOPATH in non-module mode (per @ianlancetaylor's comment), I think the behaviour in module-mode (whether inside or outside GOPATH) is undefined at best.

As you say, good error messages will help remove the confusion.

@bcmills bcmills added this to the Go1.12 milestone Sep 11, 2018
@bcmills bcmills self-assigned this Sep 11, 2018
@bcmills bcmills added the NeedsFix The path to resolution is known, but the work has not been done. label Sep 11, 2018
antong added a commit to antong/go that referenced this issue Oct 2, 2018
p = path.Dir(p) converges to either "." or "/". The current
implementation of modload.QueryPackage() has a loop that
terminates only on ".", not "/". This leads to the go command
hanging in an infinite loop if the user manages to supply
a file path starting with "/" as package path.

An example of the issue is if the user (incorrectly) attempts
to use an absolute directory path in an import statement within
a module (import "/home/bob/myproj") and then runs go list.

Fixes golang#27558
@gopherbot
Copy link
Contributor

Change https://golang.org/cl/139098 mentions this issue: cmd/go: prevent infinite loop in QueryPackage()

@golang golang locked and limited conversation to collaborators Oct 3, 2019
@rsc rsc unassigned bcmills Jun 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge modules NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

4 participants