Signals as IPC in Unix/Linux

(11). Misuse of Signals: In many OS books, signals are classified as a mechanism for inter-process communication. The rationale is that a process may send a signal to another process, causing it to execute a preinstalled signal handler function. The classification is highly debatable, if not inappropriate, for the following reasons.

. The mechanism is unreliable due to possible missing signals. Each signal is represented by a single bit in a bit-vector, which can only record one occurrence of a signal. If a process sends two or more identical signals to another process, they may show up only once in the recipient PROC. Real-time signals are queued and guaranteed to be delivered in the same order as they are sent, but an OS kernel may not support real-time signals.

. Race condition: Before processing a signal, a process usually resets the signal handler to DEFault. In order to catch another occurrence of the same signal, the process must reinstall the catcher function BEFORE the next signal arrives. Otherwise, the next signal may cause the process to terminate. Although the race condition could be prevented by blocking the same signal while executing the signal catcher, there is no way to prevent missing signals.

. Most signals have predefined meaning. Indiscriminate use of signals may not achieve commu­nication but confusion. For example, sending a SIGSEGV(11) segmentation fault signal to a looping process is like yelling to a swimmer in the water: “Your pants are on fire!”. Therefore, trying to use signals as a means of interprocess communication is over stretching the intended purpose of signals, which should be avoided.

Example 6.7. Catcher for Segmentation Faults As pointed out Chap. 2, the most common causes of segmentation faults in C programs are due to dereferencing null or invalid pointers, array out of bounds, etc. When a process encounters a invalid memory exception, it traps to the OS kernel to generate a SIGSEGV(11) signal to itself. The default handler of the SIGSEGV signal is 0, which causes the process to terminate. If the process has ignored the signal, it would return to the same bad instruction again, resulting in an infinite loop. If the user has installed a catcher for the SIGSEGV signal, it would execute the signal catcher but still return to the same bad instruction when the catcher finishes. It seems that the only option is for the process to terminate abnormally in case of any segmentation fault. This example shows how to use signal catcher and long jump to bypass the program code that caused the segmentation fault, allowing the program to continue or terminate gracefully.

/********** t7.c file **********/

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

#include <setjmp.h> // for long jump

jmp_buf env; // for saving longjmp environment

int count = 0;

void handler(int sig, siginfo_t *siginfo, void *context)

{

printf (“handler: sig=%d from PID=%d UID=%d count=%d\n”,

sig, siginfo->si_pid, siginfo->si_uid, ++count);

if (count >= 4) // let it occur up to 4 times

longjmp(env, 1234);

}

int BAD()

{

int *ip = 0;

printf(“in BAD(): try to dereference NULL pointer\n”);

*ip = 123;          // dereference a NULL pointer

printf(“should not see this line\n”);

}

int main (int argc, char *argv[])

{

int r;

struct sigaction act; memset (&act, 0, sizeof(act));

act.sa_sigaction = &handler; act.sa_flags = SA_SIGINFO;

sigaction(SIGSEGV, &act, NULL); // install SIGSEGV catcher

if ((r = setjmp(env)) == 0)      // call setjmp(env)

BAD();                       // call BAD()

else

printf(“proc %d survived SEGMENTATION FAULT: r=%d\n”,getpid(), r);

printf(“proc %d looping\n”);

while(1);

}

Figure 6.2 show the outputs of the segfault.c program.

Exercise 6.7 Modify the Example 6 program to catch divide by zero exceptions.

Source: Wang K.C. (2018), Systems Programming in Unix/Linux, Springer; 1st ed. 2018 edition.

Leave a Reply

Your email address will not be published. Required fields are marked *