Coming back to life after Segmentation Violation

前端 未结 13 2165
暗喜
暗喜 2020-12-08 11:26

Is it possible to restore the normal execution flow of a C program, after the Segmentation Fault error?

struct A {
    int x;
};
A* a = 0;

a->x = 123; /         


        
13条回答
  •  时光取名叫无心
    2020-12-08 12:17

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    void safe_func(void)
    {
        puts("Safe now ?");
        exit(0); //can't return to main, it's where the segfault occured.
    }
    
    void
    handler (int cause, siginfo_t * info, void *uap)
    {
      //For test. Never ever call stdio functions in a signal handler otherwise*/
      printf ("SIGSEGV raised at address %p\n", info->si_addr);
      ucontext_t *context = uap;
      /*On my particular system, compiled with gcc -O2, the offending instruction
      generated for "*f = 16;" is 6 bytes. Lets try to set the instruction
      pointer to the next instruction (general register 14 is EIP, on linux x86) */
      context->uc_mcontext.gregs[14] += 6; 
      //alternativly, try to jump to a "safe place"
      //context->uc_mcontext.gregs[14] = (unsigned int)safe_func;
    }
    
    int
    main (int argc, char *argv[])
    {
      struct sigaction sa;
      sa.sa_sigaction = handler;
      int *f = NULL;
      sigemptyset (&sa.sa_mask);
      sa.sa_flags = SA_SIGINFO;
      if (sigaction (SIGSEGV, &sa, 0)) {
          perror ("sigaction");
          exit(1);
      }
      //cause a segfault
      *f = 16; 
      puts("Still Alive");
      return 0;
    }
    
    $ ./a.out
    SIGSEGV raised at address (nil)
    Still Alive
    

    I would beat someone with a bat if I saw something like this in production code though, it's an ugly, for-fun hack. You'll have no idea if the segfault have corrupted some of your data, you'll have no sane way of recovering and know that everything is Ok now, there's no portable way of doing this. The only mildly sane thing you could do is try to log an error (use write() directly, not any of the stdio functions - they're not signal safe) and perhaps restart the program. For those cases you're much better off writing a superwisor process that monitors a child process exit, logs it and starts a new child process.

提交回复
热议问题