While return si_addr with offset from sigwaitinfo

2019-08-11 04:26发布

问题:

I am working on the signal handler to deal with reap signals, randomly I am getting the signal with offset when I call sigwaitinfo function. All the signal attributes are right, except for info.si_addr. This offset in info.si_addr is causing a segmentation fault.

This offset seems to be the same - I have tried removing the offset and that works, but I need a correct solution to go forward.

static void *signalHandler(void *vptr_args __attribute__((unused)))
  {
      sigset_t signal_set;
      siginfo_t info;

      sigemptyset(&signal_set);
      sigaddset(&signal_set, SIG_REAP);
      sigaddset(&signal_set, SIG_ISOC_CANCEL);
      sigaddset(&signal_set, SIGTERM);
      sigaddset(&signal_set, SIGPIPE);

      while (true) {
          int rc = sigwaitinfo(&signal_set, &info);
          //...
          if (rc > 0) 
{
            if(info.si_signo == SIG_REAP) 
               {
                 // Reap URBs after some simple checks
                 if ((info.si_code != SI_ASYNCIO) &&
                     (info.si_code != SI_KERNEL)) {
                      printf("Bad si_code %d in SIG_REAP", info.si_code);                      
                      continue;
                 } 
                   else {
                      printf("OK si_code %d in SIG_REAP", info.si_code);
                 }
                   struct usbdevfs_urb *ioctl_urb = (struct usbdevfs_urb*)info.si_addres
                  if (!ioctl_urb) {
                     printf("SIG_REAP gave NULL ioctl_urb");
                      continue;
                  }
                  UrbInfo *urbInfo = ioctl_urb->usercontext;
                  if (!urbInfo) {
                     printf("SIG_REAP gave NULL urbInfo");
                      continue;
}

回答1:

You are misusing si_addr. It is available for only a limited number of signals, and those do not include any real-time signals.

Per POSIX, si_addr is not applicable for signals other than SIGILL, SIGFPE, SIGSEGV, and SIGBUS. Linux also provides si_addr data for SIGTRAP:

SIGILL, SIGFPE, SIGSEGV, SIGBUS, and SIGTRAP fill in si_addr with the address of the fault.

No other signals provide a value for si_addr.

The source code linux/kernel/signal.c that fills in si_addr clearly shows that si_addr is not used for any signals other than those listed.

Note that per the Linux signal(7) man page:

Real-time signals are distinguished by the following:

  1. Multiple instances of real-time signals can be queued. By contrast, if multiple instances of a standard signal are delivered while that signal is currently blocked, then only one instance is queued.

  2. If the signal is sent using sigqueue(3), an accompanying value (either an integer or a pointer) can be sent with the signal. If the receiving process establishes a handler for this signal using the SA_SIGINFO flag to sigaction(2), then it can obtain this data via the si_value field of the siginfo_t structure passed as the second argument to the handler. Furthermore, the si_pid and si_uid fields of this structure can be used to obtain the PID and real user ID of the process sending the signal.

...