diff --git a/src/syscall/exec_libc2.go b/src/syscall/exec_libc2.go index b05f053bbf..bd2ce6820d 100644 --- a/src/syscall/exec_libc2.go +++ b/src/syscall/exec_libc2.go @@ -76,7 +76,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr // About to call fork. // No more allocation or calls of non-assembly functions. runtime_BeforeFork() - r1, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fork_trampoline), 0, 0, 0) + r1, _, err1 = rawSyscall(forkTrampoline, 0, 0, 0) if err1 != 0 { runtime_AfterFork() return 0, err1 @@ -260,6 +260,6 @@ childerror: // send error code on pipe rawSyscall(abi.FuncPCABI0(libc_write_trampoline), uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) for { - rawSyscall(abi.FuncPCABI0(libc_exit_trampoline), 253, 0, 0) + rawSyscall(exitTrampoline, 253, 0, 0) } } diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go index 902d6e77e1..346e6862cd 100644 --- a/src/syscall/syscall_darwin.go +++ b/src/syscall/syscall_darwin.go @@ -17,6 +17,34 @@ import ( "unsafe" ) +// These are called from exec_libc2.go in the child of fork. +// The names differ between macOS and OpenBSD, so we need +// to declare the specific ones used here to keep the exec_libc2.go +// code portable. +// +// We use __fork and __exit, not fork and exit, to avoid the libc atfork +// and atexit handlers. The atfork handlers have caused fork child +// hangs in the past (see #33565, #56784). The atexit handlers have +// not, but the non-libc ports all invoke the system call, so doing +// the same here makes sense. In general we wouldn't expect +// atexit handlers to work terribly well in a fork child anyway. +// (Also, perhaps the atfork handlers clear the atexit handlers, +// in which case we definitely need to avoid calling the libc exit +// if we bypass the libc fork.) +// +// Other calls that are made in the child after the fork are +// ptrace, setsid, setpgid, getpid, ioctl, chroot, setgroups, +// setgid, setuid, chdir, dup2, fcntl, close, execve, and write. +// Those are all simple kernel wrappers that should be safe +// to be called directly. The fcntl and ioctl functions do run +// some code around the kernel call, but they don't call any +// other functions, so for now we keep using them instead of +// calling the lower-level __fcntl and __ioctl functions. +var ( + exitTrampoline = abi.FuncPCABI0(libc___exit_trampoline) + forkTrampoline = abi.FuncPCABI0(libc___fork_trampoline) +) + type SockaddrDatalink struct { Len uint8 Family uint8 @@ -202,11 +230,12 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1) //sys writev(fd int, iovecs []Iovec) (cnt uintptr, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) //sys munmap(addr uintptr, length uintptr) (err error) -//sysnb fork() (pid int, err error) +//sysnb __fork() (pid int, err error) //sysnb ioctl(fd int, req int, arg int) (err error) //sysnb ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_ioctl //sysnb execve(path *byte, argv **byte, envp **byte) (err error) //sysnb exit(res int) (err error) +//sysnb __exit(res int) (err error) //sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) //sys fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (val int, err error) = SYS_fcntl //sys unlinkat(fd int, path string, flags int) (err error) diff --git a/src/syscall/syscall_openbsd_libc.go b/src/syscall/syscall_openbsd_libc.go index 15b68fd0fc..ff9fa00259 100644 --- a/src/syscall/syscall_openbsd_libc.go +++ b/src/syscall/syscall_openbsd_libc.go @@ -10,6 +10,11 @@ import ( "internal/abi" ) +var ( + exitTrampoline = abi.FuncPCABI0(libc_exit_trampoline) + forkTrampoline = abi.FuncPCABI0(libc_fork_trampoline) +) + func init() { execveOpenBSD = execve } diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go index 0ccdaf2d0e..2ad03801b2 100644 --- a/src/syscall/zsyscall_darwin_amd64.go +++ b/src/syscall/zsyscall_darwin_amd64.go @@ -1714,8 +1714,8 @@ func libc_munmap_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func fork() (pid int, err error) { - r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_fork_trampoline), 0, 0, 0) +func __fork() (pid int, err error) { + r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc___fork_trampoline), 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1723,9 +1723,9 @@ func fork() (pid int, err error) { return } -func libc_fork_trampoline() +func libc___fork_trampoline() -//go:cgo_import_dynamic libc_fork fork "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc___fork __fork "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -1781,6 +1781,20 @@ func libc_exit_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func __exit(res int) (err error) { + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc___exit_trampoline), uintptr(res), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc___exit_trampoline() + +//go:cgo_import_dynamic libc___exit __exit "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { var _p0 unsafe.Pointer if len(mib) > 0 { diff --git a/src/syscall/zsyscall_darwin_amd64.s b/src/syscall/zsyscall_darwin_amd64.s index 563083d441..1815703803 100644 --- a/src/syscall/zsyscall_darwin_amd64.s +++ b/src/syscall/zsyscall_darwin_amd64.s @@ -219,14 +219,16 @@ TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_mmap(SB) TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_munmap(SB) -TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fork(SB) +TEXT ·libc___fork_trampoline(SB),NOSPLIT,$0-0 + JMP libc___fork(SB) TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_ioctl(SB) TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) +TEXT ·libc___exit_trampoline(SB),NOSPLIT,$0-0 + JMP libc___exit(SB) TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go index 09bf34bb3c..559bb49c4b 100644 --- a/src/syscall/zsyscall_darwin_arm64.go +++ b/src/syscall/zsyscall_darwin_arm64.go @@ -1714,8 +1714,8 @@ func libc_munmap_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func fork() (pid int, err error) { - r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_fork_trampoline), 0, 0, 0) +func __fork() (pid int, err error) { + r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc___fork_trampoline), 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1723,9 +1723,9 @@ func fork() (pid int, err error) { return } -func libc_fork_trampoline() +func libc___fork_trampoline() -//go:cgo_import_dynamic libc_fork fork "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc___fork __fork "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -1781,6 +1781,20 @@ func libc_exit_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func __exit(res int) (err error) { + _, _, e1 := rawSyscall(abi.FuncPCABI0(libc___exit_trampoline), uintptr(res), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc___exit_trampoline() + +//go:cgo_import_dynamic libc___exit __exit "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { var _p0 unsafe.Pointer if len(mib) > 0 { diff --git a/src/syscall/zsyscall_darwin_arm64.s b/src/syscall/zsyscall_darwin_arm64.s index 0567a42fa3..1666cf985c 100644 --- a/src/syscall/zsyscall_darwin_arm64.s +++ b/src/syscall/zsyscall_darwin_arm64.s @@ -219,14 +219,16 @@ TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_mmap(SB) TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_munmap(SB) -TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 - JMP libc_fork(SB) +TEXT ·libc___fork_trampoline(SB),NOSPLIT,$0-0 + JMP libc___fork(SB) TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_ioctl(SB) TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) +TEXT ·libc___exit_trampoline(SB),NOSPLIT,$0-0 + JMP libc___exit(SB) TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0