Skip to content

syscall: rawVforkSyscall works differently outside syscall package via go:link syscall.rawVforkSyscall #71892

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

Closed
criyle opened this issue Feb 22, 2025 · 2 comments
Labels
BugReport Issues describing a possible bug in the Go implementation. compiler/runtime Issues related to the Go compiler and/or runtime.

Comments

@criyle
Copy link

criyle commented Feb 22, 2025

Go version

go version go1.24.0 linux/amd64

Output of go env in your module/workspace:

AR='ar'
CC='cc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='c++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/criyle/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/criyle/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1441692700=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/criyle/project/test/go.mod'
GOMODCACHE='/home/criyle/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/criyle/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/linuxbrew/.linuxbrew/Cellar/go/1.24.0/libexec'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/criyle/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/linuxbrew/.linuxbrew/Cellar/go/1.24.0/libexec/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.0'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

Trying to use vfork via rawVforkSyscall outside of the syscall package

package main

import (
	"fmt"
	"syscall"
	_ "unsafe" // to use go:linkname
)

func main() {
	fmt.Println("start")
	pid2, err := testVfork()
	if err != syscall.Errno(0) {
		fmt.Printf("%s\n", err)
	}
	syscall.Wait4(pid2, nil, 0, nil)
	fmt.Println("finished")
}

//go:norace
func testVfork() (pid int, err syscall.Errno) {
	upid, err := testVforkChild()
	afterFork()
	if err != 0 {
		return 0, err
	}
	pid = int(upid)
	return pid, 0
}

//go:noinline
//go:norace
//go:nocheckptr
func testVforkChild() (pid uintptr, err1 syscall.Errno) {
	var flags uintptr = syscall.CLONE_VFORK | syscall.CLONE_VM | uintptr(syscall.SIGCHLD)

	beforeFork()
	pid, err1 = rawVforkSyscall(syscall.SYS_CLONE, flags, 0, 0)
	if err1 != 0 || pid != 0 {
		return
	}
	afterForkInChild()

	// child
	syscall.RawSyscall(syscall.SYS_EXIT, 0, 0, 0)

	// should not reach... however reached by parent
	for {
		syscall.RawSyscall(syscall.SYS_EXIT_GROUP, 253, 0, 0)
	}
}

//go:linkname beforeFork syscall.runtime_BeforeFork
func beforeFork()

//go:linkname afterFork syscall.runtime_AfterFork
func afterFork()

//go:linkname afterForkInChild syscall.runtime_AfterForkInChild
func afterForkInChild()

//go:linkname rawVforkSyscall syscall.rawVforkSyscall
func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1 uintptr, err syscall.Errno)

What did you see happen?

The program exited with exit code 253 and only printed start, it suggests the parent thread resumes at the point where child calls exit, and continued to exit_group(253), which should never reach.

If testVfork copied to syscall package (just for testing), and calls rawVforkSyscall directly, the program exits normally as expected. There might be behaviour difference with the linker.

Using go tool objdump, the above code generates CALL syscall.rawVforkSyscall(SB) while the function within syscall package generates CALL syscall.rawVforkSyscall.abi0(SB). However, linking syscall.rawVforkSyscall.abi0 via go:linkname is not possible (relocation target syscall.rawVforkSyscall.abi0 not defined).

What did you expect to see?

The program exited with exit code 0 and prints start, finished.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Feb 22, 2025
@gabyhelp gabyhelp added the BugReport Issues describing a possible bug in the Go implementation. label Feb 22, 2025
@ianlancetaylor
Copy link
Member

Calling a function written in assembly, like rawVforkSyscall using go:linkname is not supported.

Just copy the assembler code into your own package.

@ianlancetaylor ianlancetaylor closed this as not planned Won't fix, can't repro, duplicate, stale Feb 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BugReport Issues describing a possible bug in the Go implementation. compiler/runtime Issues related to the Go compiler and/or runtime.
Projects
None yet
Development

No branches or pull requests

4 participants