linuxsignalsmanpagesigaction

Use of .sa_sigaction and .sa_handler in same project(man page clarification)


While looking up the man pages for sigaction, I stumbled upon a confusing note in the Linux man pages:

On some architectures a union is involved: do not assign to both sa_handler and sa_sigaction(sigaction man page).

There are two possible ways to read it:

  1. Does this mean, as I understand it, that you are not allowed to set .sa_sigaction and .sa_handler in the same struct sigaction.
  2. Or is one only allowed to use either .sa_sigaction OR .sa_handler in the whole project?
struct sigaction sigactionArray[SIGNAL_SIGACTION_ARRAY_SIZE] = {
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK},
   {.sa_handler = SIG_IGN, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_IGN, .sa_flags = SA_NODEFER},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK},
   {.sa_handler = SIG_IGN, .sa_flags = SA_NODEFER},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_IGN, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_IGN, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_IGN, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_IGN, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_handler = SIG_DFL, .sa_flags = SA_NODEFER},
   {.sa_sigaction = HandleBacktraceSignals, .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK}
};

According to interpretation 1. the above piece of code would be fine, but when definition 2. is right, it would be invalid since I mix.

Which one is true? Note: On my architecture, it is defined as a union


Solution

  • It's just talking about the same structure. It explains why: they might be part of a union, so they use the same memory in the structure. E.g. it might actually be like:

    struct sigaction {
        union {
            void     (*sa_handler)(int);
            void     (*sa_sigaction)(int, siginfo_t *, void *);
        },
        sigset_t   sa_mask;
        int        sa_flags;
        void     (*sa_restorer)(void);
    };
    

    Therefore, writing to one of them overwrites the other.