Current vfork implementation doesn't work with CLONE_VM. If we naively passthrough CLONE_VM then host stack will get garbaged by the child. Same goes for TLS. And ThreadState. Maybe other things?
The way we fix the TLS issue for threads is creating a pthread so it creates a TLS and then cloning that. In a utopia maybe we don't depend on libc and use tp however we want... (but then we load in libc anyway because of thunks and it freaks out cus of our tp) Anyway, we could fix vfork tls issues in a similar fashion.
For stack, it would probably need a custom stack to be created... It would need to happen before the fork, and swap the stack in assembly after the fork. Gotta be careful not to leak the stack when the child exits though... as it exists on the parent address space.
For ThreadState there needs to be a deep copy of the registers and other stuff... that also needs to be cleaned up after it exits.
The clean ups can happen from the parent side because it will wait for the child to finish.
Ideally we should perhaps merge the fork/vfork/clone interfaces and handle the specific flags differently.....
Here's a test
#include <signal.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
#include "common.h"
// vfork cannot afford to call functions cus they may corrupt the host stack, so we call
// the syscall in assembly directly. This tests CLONE_VM is really enabled and the memory write goes through
int __attribute__((naked)) vfork_safe(void* addr) {
asm(R"(
.intel_syntax noprefix
mov eax, 58
syscall
test eax, eax
jnz .skip
mov dword ptr[rdi], 1
mov eax, 60
syscall
hlt
.skip:
ret
.att_syntax prefix
)");
}
int main() {
int* mem = (int*)malloc(4);
*mem = 0;
int result = vfork_safe(mem);
if (result == 0) {
// won't be reached...
raise(SIGSEGV);
} else {
// By this point child has already exited because vfork returned, but
// ensure it anyway for the emulator
int status;
result = waitpid(result, &status, 0);
if (!WIFEXITED(status)) {
return 1;
}
return *mem ? FELIX86_BTEST_SUCCESS : 1;
}
}
Current vfork implementation doesn't work with CLONE_VM. If we naively passthrough CLONE_VM then host stack will get garbaged by the child. Same goes for TLS. And ThreadState. Maybe other things?
The way we fix the TLS issue for threads is creating a pthread so it creates a TLS and then cloning that. In a utopia maybe we don't depend on libc and use
tphowever we want... (but then we load in libc anyway because of thunks and it freaks out cus of ourtp) Anyway, we could fix vfork tls issues in a similar fashion.For stack, it would probably need a custom stack to be created... It would need to happen before the fork, and swap the stack in assembly after the fork. Gotta be careful not to leak the stack when the child exits though... as it exists on the parent address space.
For ThreadState there needs to be a deep copy of the registers and other stuff... that also needs to be cleaned up after it exits.
The clean ups can happen from the parent side because it will wait for the child to finish.
Ideally we should perhaps merge the fork/vfork/clone interfaces and handle the specific flags differently.....
Here's a test