setevoy
setevoy

Reputation: 4662

Using getpid() with clone() results in SIGSEGV

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

Answers (1)

Marco Bonelli
Marco Bonelli

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 to clone(). Stacks grow downward on all processors that run Linux (except the HP PA processors), so child_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

Related Questions