From 2d0ac5a42da8d0b755efae759a72e64e6b983802 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Thu, 1 May 2025 15:04:17 -0700 Subject: [PATCH] os,runtime: make sure executable path is fully resolved at process init --- src/os/executable_darwin.go | 11 +------ src/runtime/os_darwin.go | 65 ++++++++++++++++++++++++++++++++++--- src/runtime/os_linux.go | 4 +++ src/runtime/runtime_unix.go | 3 ++ 4 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/os/executable_darwin.go b/src/os/executable_darwin.go index e689db23fb..7c65a90c3d 100644 --- a/src/os/executable_darwin.go +++ b/src/os/executable_darwin.go @@ -6,14 +6,5 @@ package os func runtime_executable_path() string func Executable() (string, error) { - p := runtime_executable_path() - if p != "" && p[0] == '/' { - // absolute path - return p, nil - } - cwd, err := Getwd() - if err != nil { - return "", err - } - return joinPath(cwd, p), nil + return runtime_executable_path(), nil } diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index df5c598807..3a31a1dbbe 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -232,10 +232,18 @@ func call_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) uintptr //go:linkname os_runtime_executable_path os.runtime_executable_path func os_runtime_executable_path() string { - argv := (*unsafe.Pointer)(unsafe.Pointer(main_argv)) + return executablePath +} + +var executablePath string +func platform_argv(argc int32, argv *unsafe.Pointer) { + executablePath = executable_path(argc, argv) +} + +func executable_path(argc int32, argv *unsafe.Pointer) string { // skip over argv - argv = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(argv), (uintptr(main_argc)+1)*unsafe.Sizeof(argv))) + argv = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(argv), (uintptr(argc)+1)*unsafe.Sizeof(argv))) // skip over envv for (*argv) != nil { @@ -251,11 +259,21 @@ func os_runtime_executable_path() string { length: length, ptr: (*byte)(cstr), } - executablePath := *(*string)(unsafe.Pointer(&argString)) + path := *(*string)(unsafe.Pointer(&argString)) // strip "executable_path=" prefix if available, it's added after OS X 10.11. - executablePath = stringsTrimPrefix(executablePath, "executable_path=") - return executablePath + path = stringsTrimPrefix(path, "executable_path=") + + if path != "" && path[0] == '/' { + // absolute path + return path + } + + cwd := getcwd() + if cwd != "" { + path = joinPath(cwd, path) + } + return path } func stringsTrimPrefix(s, prefix string) string { @@ -264,3 +282,40 @@ func stringsTrimPrefix(s, prefix string) string { } return s } + +func joinPath(dir, name string) string { + if len(dir) > 0 && dir[len(dir)-1] == '/' { + return dir + name + } + return dir + "/" + name +} + +// from syscall +func getcwd() string { + const pathMax = 1024 + var buf [4 * pathMax]byte + s := libc_getcwd(&buf[0], uint(len(buf))) + if s == nil { + return "" + } + n := clen(buf[:]) + if n < 1 { + return "" + } + return string(buf[:n]) +} + +// clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte. +func clen(n []byte) int { + for i := 0; i < len(n); i++ { + if n[i] == 0 { + return i + } + } + return len(n) +} + +// char *getcwd(char *buf, size_t size) +// +//export getcwd +func libc_getcwd(buf *byte, size uint) *byte diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index 0ae105c5fc..7544af1ad1 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -157,3 +157,7 @@ func fcntl(fd int32, cmd int32, arg int32) (ret int32, errno int32) { errno = *libc_errno_location() return } + +func platform_argv(argc int32, argv *unsafe.Pointer) { + // nothing +} diff --git a/src/runtime/runtime_unix.go b/src/runtime/runtime_unix.go index 99f28411f3..658ac5b418 100644 --- a/src/runtime/runtime_unix.go +++ b/src/runtime/runtime_unix.go @@ -95,6 +95,9 @@ func main(argc int32, argv *unsafe.Pointer) int { // The run function has been moved to a separate (non-inlined) function so // that the correct stack pointer is read. stackTop = getCurrentStackPointer() + + platform_argv(main_argc, main_argv) + runMain() // For libc compatibility.