Search code examples
segmentation-faultsignalschild-process

How to make the child process handle SIGSEGV by itself


I have a program that calls run to do something.
In run running, which will generate a SIGSEGV and catch this signal and normal return by sigsetjmp/siglongjmp.
However, if i create multiple child processes to run the function run, the run seems to be unable to catch its own SIGSEGV signal.
Therefore, my question is how does the child process capture its own SIGSEGV and return normally?
Here, my example code.

struct sigaction act, oact;
static  sigjmp_buf jmpbuf;
int run(void * arg);
static void sig_handle(int signum, siginfo_t* siginfo, void* context){                 
  siglongjmp(jmpbuf,1);                                  
} 

#define STACK_SIZE (1024 * 1024)
int main()
{
  pid_t pid;
  pid_t pid1;
  char *stack;
  char *stackTop;
  stack = (char*)malloc(STACK_SIZE);
  if (stack == NULL){
    fprintf(stderr,"malloc failed\n");  
    exit(-1);
  }
  stackTop = stack+STACK_SIZE;
 
  pid = clone(run, stackTop, CLONE_VM|SIGCHLD, (void*)2);
  if (pid == -1){
    fprintf(stderr,"clone failed\n");
    exit(-1);
  }

  for(int i = 0; i < 3; ++i) 
    run((void *)i);

  if (waitpid(pid, NULL, 0) == -1){    /* Wait for child */
      fprintf(stderr,"clone close failed\n");
      exit(-1);
     }
 
  return 0;
}

int run(void * arg){
  act.sa_sigaction = sig_handle;
  sigemptyset(&act.sa_mask);
  act.sa_flags = SA_SIGINFO|SA_ONSTACK;
  if(sigaction(SIGSEGV, &act, &oact)<0)
    exit(-1);

  int args = (uint64_t)arg;
  if(sigsetjmp(jmpbuf,1)==0){
    if(args==2)
        sleep(1);
    *(uint64_t *)0 = 1;
  }else 
    sleep(1);
  
  return 0;
}

Solution

  • However, if i create multiple child processes

    The clone() function you are using does not create child processes, it creates threads within the current process, all sharing the address space with the parent (CLONE_VM flag).

    While this can be made to work, it's extremely tricky to do this correctly, and there is a high chance that you aren't. In particular, you can not call any libc function within the clone()d process (and you do call sigaction(); that's a no-no).

    You also can't use a single jmpbuf if it is shared by multiple threads.

    The simple solution is to actually create child processes (using fork()).