Reputation: 4662
I'm trying to run a simple clone()
using the next code:
#define _GNU_SOURCE
#include <linux/sched.h>
#include <stdio.h>
#include <sched.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int child_func(void* arg) {
// printf("Child is running with PID %d\n", getpid());
printf("Child is running\n");
return 0;
}
int main() {
printf("main() started\n");
pid_t child_pid = clone(child_func, malloc(4096), SIGCHLD, NULL);
pid_t parent_pid = getpid();
printf("Parent pid: %lu\n", parent_pid);
printf("Child pid: %lu\n", child_pid);
}
And all good here:
$ ./clone_example main() started Parent pid: 9200 Child pid: 9201 Child is running
Until I'm changing the child_func()
by adding the getpid()
execution:
...
int child_func(void* arg) {
printf("Child is running with PID %d\n", getpid());
// printf("Child is running\n");
return 0;
}
...
After re-compiling this code - the child_func()
starts failing.
The console output looks like:
$ ./clone_example main() started Parent pid: 11085 Child pid: 11086
And if run with the strace
:
$ strace -o clone_example.log -ff ./clone_example main() started Parent pid: 11655 Child pid: 11656
In the thread's log clone_example.log.11656
I see the next:
> --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x562696b1dff8} --- > +++ killed by SIGSEGV (core dumped) +++
Why so? What am I doing wrong here?
Upvotes: 3
Views: 328
Reputation: 69367
From man 2 clone
:
The
child_stack
argument specifies the location of the stack used by the child process. Since the child and calling process may share memory, it is not possible for the child process to execute in the same stack as the calling process. The calling process must therefore set up memory space for the child stack and pass a pointer to this space toclone()
. Stacks grow downward on all processors that run Linux (except the HP PA processors), sochild_stack
usually points to the topmost address of the memory space set up for the child stack.
Your child is running into segmentation fault because the stack grows down and you are passing a pointer to the start of a newly allocated memory area, when you should pass a pointer to the end of such area. This only happens when you add another function call (getpid()
) because without that call your child process is not using as much stack.
Correct call would be:
pid_t child_pid = clone(child_func, ((uint8_t*)malloc(4096)) + 4095, SIGCHLD, NULL);
PS: I'm guessing that inline call to malloc()
was just to simplify the example, but you should check the return value of malloc()
before passing it to the child.
Upvotes: 3