4

I've been carefully reading the linux man page for clone(), and I understand the difference between the clone() wrapper and the "raw" system call. But what I don't understand is why the parent process needs to allocate a stack for the child, even if CLONE_VM is not used in the wrapper.

Does the wrapper simply ignore the stack argument if CLONE_VM is not used? Why require it at all then? The raw system call allows it to be null which makes sense, but I don't understand why the wrapper requires this. Will the wrapper make the child and parent share memory even if you don't tell it to?

5

The required stack argument goes hand-in-hand with the fn argument. The raw kernel syscall doesn’t always need a stack because it behaves like fork: execution in the child starts at the return of the system call. The libc wrapper then needs to set things up to call fn, and to do so, it needs the stack (and has always done so).

As a result, a stack is always required when calling the wrapper, to pass information across the clone system call to the code which calls the fn function (thread_start in the glibc code).

1
  • Note that, if it didn't always call a function in the child, the clone function would need to have the "returns twice" property which has all sorts of gotchas. – R.. GitHub STOP HELPING ICE Apr 26 at 15:09
2

I believe I've found the answer on my own. Looking at the x86-64 source file for the clone wrapper (clone.s) I found this interesting piece of code:

movq %rdi,0(%rsi)

This places the function pointer into the child process stack. This happen right before the syscall for clone. If my understanding is correct, then this causes the child process to return to the function that was passed to the wrapper. This explains why the wrapper needs a stack argument, so that it can place the function address on it. This seems to mean that the stack only needs to be large enough to fit the function pointer and arg. Im not sure why the man page doesn't explain this, or maybe I missed something when reading it

2
  • 1
    It doesn’t cause the child process to return directly to the given function; it’s handled explicitly in thread_start. It’s not pushed as a return address (as one could perhaps expect). The system call returns to test %rax, %rax in both the parent and the child. Regarding your last comment, the man pages usually explain the what and sometimes the how, but not so much the why... – Stephen Kitt Apr 26 at 6:42
  • 1
    I see you’d actually posted your answer before I wrote mine; for whatever reason it wasn’t displayed when I read your question... My answer wasn’t meant as a correction of yours, which is largely correct. – Stephen Kitt Apr 26 at 6:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.