-
Notifications
You must be signed in to change notification settings - Fork 30
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
syscall(linux): forkAndExecInChild #959
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #959 +/- ##
==========================================
+ Coverage 81.58% 81.61% +0.03%
==========================================
Files 53 53
Lines 9050 9067 +17
==========================================
+ Hits 7383 7400 +17
Misses 1516 1516
Partials 151 151 ☔ View full report in Codecov by Sentry. |
39ecf9e
to
8dee005
Compare
53da08a
to
adde0ab
Compare
The wrapper is accurate, the reason why the function is different from Go's is that libc wraps Clone in its way. Raw Syscall may like(x86-64): long clone(unsigned long flags, void *stack,
int *parent_tid, int *child_tid,
unsigned long tls); In libc, it may like: int clone(int (*fn)(void *_Nullable), void *stack, int flags,
void *_Nullable arg, ... /* pid_t *_Nullable parent_tid,
void *_Nullable tls,
pid_t *_Nullable child_tid */ ); Acutally, the stack can be nullable, however, libc does a force verification for stack: Code from gblic ENTRY (__clone)
cmp r0, 0 /* @fn can't be NULL. */
and r1,r1,-4 /* @child_stack be 4 bytes aligned per ABI. */
cmp.ne r1, 0 /* @child_stack can't be NULL. */
bz L (__sys_err) In libc, stack cannot be nullable because of calling the fn. When you don't need to call fn, the stack param can be zero. |
Good investgation! We may use the c.syscall to call the clone function from core like go vForkSyscall , to avoid libc's wrapper check. |
f4cfdd0
to
230e3ea
Compare
when excute clone with log output println("Attempting clone with flags:", flags)
ret := os.Syscall(syscall.SYS_CLONE, flags, 0)
if ret >= 0 {
if ret == 0 {
println("clone succeeded, now in child")
} else {
println("clone succeeded now in parent")
}
pid = uintptr(ret)
err1 = Errno(0)
} else {
pid = 0
err1 = Errno(os.Errno())
println("clone failed", err1)
} in my docker's linux will got
but in ci ,only got
|
when set the clone flag only use https://github.com/goplus/llgo/actions/runs/12862918395/job/35858617503?pr=959 The Go origin implement is:
llgo show use CLONE_VFORK only to clone normally
https://www.man7.org/linux/man-pages/man2/clone.2.html In contrast to the glibc wrapper, the raw clone() system call |
90263e9
to
50d3a12
Compare
50d3a12
to
1b536bf
Compare
result
before use exec.command in linux
got
now
in the ci , use the exec.command to call nm tool,it can work normally.goplus/llcppg#160
resolution
The libc wrapper's clone function cannot create processes with an empty child stack. Therefore, we need to directly use syscall to invoke the system's clone function instead of using libc's clone implementation.
On Linux x86, when creating a process using clone with CLONE_VM flag (similar to Go's approach), it sets up memory sharing between parent and child processes. This can lead to unexpected parent process termination. Go addresses this on Linux x86 through assembly optimizations, allowing parent and child processes to share memory while ensuring that executing exec doesn't clear the shared stack, thus enabling normal execution.
question
other question(resolved)
in linux, go use clone to fork a child process,current is temp use fork to create a child process
src/syscall/exec_linux.go
in above code,only pass two param to clone, but in the signature of c,have three params
and if we only pass the flags & arg through call c.clone
will got
its error output like use clone without child_stack , got Invalid argument
in the under asm code,it have some operate
so in current resolution, use the syscall to call the clone instead the libc wrapper clone;
from #959 (comment) 's resolution