|
1 | 1 | - [Signals](#signals)
|
| 2 | + * [Types of Signals](#types-of-signals) |
2 | 3 | * [SIGILL](#sigill)
|
3 | 4 | * [SIGSEGV](#sigsegv)
|
4 | 5 | + [Segmentation fault](#segmentation-fault)
|
|
8 | 9 | * [SIGSYS](#sigsys)
|
9 | 10 | * [SIGTRAP](#sigtrap)
|
10 | 11 | * [SIGTERM](#sigterm)
|
11 |
| -- [Raising a Signal](#raising-a-signal) |
12 | 12 | - [Setting Signal Handler](#setting-signal-handler)
|
| 13 | +- [Examples](#examples) |
| 14 | + * [SIGINT_Handler](#sigint-handler) |
| 15 | + * [SIGSEGV_Handler](#sigsegv-handler) |
| 16 | +- [Raising a Signal](#raising-a-signal) |
| 17 | + |
13 | 18 |
|
14 | 19 |
|
15 | 20 | # Signals
|
16 |
| -Signals in computers are a way of communication between the process and the OS. |
17 |
| -When a running program undergoes some serious error then the OS sends a signal to |
18 |
| -the process and the process further may not execute. |
19 |
| -Some processes may have a signal handler which does some important tasks before the |
| 21 | +Signals are a communication mechanism between a process and the operating system. When a running program encounters a significant error, the OS sends a signal to that process. Some processes may have a signal handler which does some important tasks before the |
20 | 22 | process leaves the CPU.
|
21 |
| -Signal and interrupt are basically same but a small distinction exists i.e interrupts |
22 |
| -are generated by the processor and handled by the kernel but signals are generated by |
23 |
| -the kernel and handled by the process. |
24 |
| -Error signals generally causes termination of the program and a core dump file is |
25 |
| -created named core, which stores the state of the process at the moment of termination. |
26 |
| -This file can be investigated using debugger to know the cause of program termination. |
| 23 | + |
| 24 | + |
| 25 | +Signals and interrupts serve similar purposes, but they differ in their origin and handling mechanisms. Interrupts originate from the processor and are managed by the operating system's kernel. In contrast, signals are generated by the kernel and are managed by the individual process to which they are sent. |
| 26 | + |
| 27 | + |
| 28 | +## Types of Signals |
| 29 | +There are various types of signals, each corresponding to different events. |
27 | 30 | ## SIGILL
|
28 |
| -This signal denotes illegal instruction. When a garbage instruction or instruction |
29 |
| -which a program has no privilege to execute, is executed then this signal is |
30 |
| -generated. |
31 |
| -C does not produce illegal instruction so there is no chance of facing such error |
32 |
| -signal, as the probable cause may be that the object file may be corrupted. |
33 |
| -This signal is also generated when stack overflow occurs. |
| 31 | +This signal in Unix-like operating systems is sent to a process when it attempts to execute an illegal, malformed, unknown, or privileged instruction. |
34 | 32 | ## SIGSEGV
|
35 |
| -The signal is generated when process tries to access memory location not |
36 |
| -allocated to it, like de-referencing a wild pointer which leads to |
37 |
| -“segmentation fault”. |
| 33 | +The signal is generated when process tries to access memory location which is not allocated to it. |
38 | 34 |
|
39 | 35 | ### Segmentation fault
|
40 | 36 | The following are some typical causes of a segmentation fault:
|
41 | 37 | 1. Attempting to access a nonexistent memory address (outside process's address space)
|
42 | 38 | 2. Attempting to access memory the program does not have rights to (such as kernel structures in process context)
|
43 | 39 | 3. Attempting to write read-only memory (such as code segment)
|
44 | 40 |
|
45 |
| -The above incidents will happens while dereferencing or assigning null pointer/ wild pointer/ dangling pointer, heap overflow, stack overflow. |
| 41 | + |
46 | 42 | When you access an array index, C and C++ don't do bound checking. Segmentation faults only happen when you try to
|
47 | 43 | read or write to a page that was not allocated (or try to do something on a page which isn't permitted,
|
48 | 44 | e.g. trying to write to a read-only page), but since pages are usually pretty big
|
49 | 45 | (multiples of a few kilobytes), it often leaves you with lots of room to overflow.
|
| 46 | + |
| 47 | + |
| 48 | +``` |
| 49 | +int main() { |
| 50 | + // Define an array with a small size |
| 51 | + int array[5] = {0, 1, 2, 3, 4}; |
| 52 | +
|
| 53 | + std::cout << "Original array values:\n"; |
| 54 | + for (int i = 0; i < 5; i++) { |
| 55 | + std::cout << "array[" << i << "] = " << array[i] << "\n"; |
| 56 | + } |
| 57 | +
|
| 58 | + // Overflowing the array |
| 59 | + // Writing beyond the bounds of the array |
| 60 | + std::cout << "\nWriting beyond the bounds of the array...\n"; |
| 61 | + for (int i = 0; i < 100; |
| 62 | + i++) { // This loop intentionally goes well beyond the array's bounds |
| 63 | + array[i] = i; |
| 64 | + } |
| 65 | + return 0; |
| 66 | +} |
| 67 | +``` |
| 68 | + |
50 | 69 | By setting the followings flag you can find the issue:
|
| 70 | + |
| 71 | + |
51 | 72 | ```
|
52 | 73 | set(CMAKE_CXX_FLAGS "-fsanitize=address ${CMAKE_CXX_FLAGS}")
|
53 | 74 | set(CMAKE_CXX_FLAGS "-fno-omit-frame-pointer ${CMAKE_CXX_FLAGS}")
|
@@ -77,38 +98,99 @@ Unlike `SIGKILL`, this signal can be blocked, handled, and ignored. It is
|
77 | 98 | the normal way to politely ask a program to terminate. The shell command
|
78 | 99 | kill generates `SIGTERM` by default.
|
79 | 100 |
|
80 |
| -# raising a Signal |
81 |
| -The `<csignal>` header file declared the function `raise()` to handle a particular signal. Signal learns some unusual behavior in a program, and calls the signal handler. It is implemented to check if the default handler will get called or it will be ignored. |
82 |
| -Syntax: |
83 |
| -```cpp |
84 |
| -int raise ( int signal_ ) |
85 |
| -``` |
| 101 | + |
86 | 102 | # Setting Signal Handler
|
87 |
| -Sets the handler for signal sig |
88 |
| -```cpp |
89 |
| -signal(int sig, /*signal-handler*/* handler); |
90 |
| -``` |
| 103 | +create the signal handler function: |
91 | 104 |
|
92 |
| -defining a signal handler: |
93 | 105 | ```cpp
|
94 |
| -sig_atomic_t s_value = 0; |
95 |
| -void handle(int signum) |
96 |
| -{ |
97 |
| - s_value = signum; |
| 106 | +void signalHandler(int signum) { |
| 107 | + std::cout << "signal (" << signum << ") received.\n"; |
| 108 | + // Cleanup and close up logic |
| 109 | + exit(signum); |
98 | 110 | }
|
99 | 111 | ```
|
| 112 | +
|
100 | 113 | setting the handler for a specific signal:
|
101 | 114 | ```cpp
|
102 |
| -//SIGILL,SIGINT,SIGSEGV,SIGTERM,SIGABRT,SIGFPE |
103 |
| -signal(SIGTERM, handle); |
| 115 | +
|
| 116 | +int main() { |
| 117 | + // Register signal SIGINT ( or any of SIGILL,SIGINT,SIGSEGV,SIGTERM,SIGABRT,SIGFPE) and signal handler |
| 118 | + signal(SIGINT, signalHandler); |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | + |
| 123 | + |
| 124 | +# Examples |
| 125 | +## SIGINT_Handler |
| 126 | +In the following example signal that is being handled is `SIGINT`. This signal is typically sent when the user presses `Ctrl+C` in the terminal. The SIGINT_Handler function in the example is specifically set up to catch and handle the SIGINT signal. |
| 127 | +``` |
| 128 | +#include <csignal> |
| 129 | +#include <iostream> |
| 130 | +
|
| 131 | +
|
| 132 | +// Signal handler function |
| 133 | +void SIGINT_Handler(int signum) { |
| 134 | + std::cout << "Interrupt signal (" << signum << ") received.\n"; |
| 135 | + // Cleanup and close up logic |
| 136 | + exit(signum); |
| 137 | +} |
| 138 | +
|
| 139 | +int main() { |
| 140 | + // Register signal SIGINT and signal handler |
| 141 | + signal(SIGINT, SIGINT_Handler); |
| 142 | +
|
| 143 | + while(1) { |
| 144 | + std::cout << "Waiting for signal..." << std::endl; |
| 145 | + sleep(1); |
| 146 | + } |
| 147 | +
|
| 148 | + return 0; |
| 149 | +} |
| 150 | +``` |
| 151 | + |
| 152 | +## SIGSEGV_Handler |
| 153 | + |
| 154 | +``` |
| 155 | +#include <csignal> |
| 156 | +#include <cstdlib> // for exit() |
| 157 | +#include <iostream> |
| 158 | +#include <unistd.h> // getpid() |
| 159 | +
|
| 160 | +void SIGSEGV_Handler(int signum) { |
| 161 | + std::cout << "oh my god! segmenation fault happened" << std::endl; |
| 162 | + printf("Process %d got signal %d\n", getpid(), signum); |
| 163 | + // kill(getpid(), signum); |
| 164 | + exit(signum); |
| 165 | +} |
| 166 | +
|
| 167 | +int main() { |
| 168 | + signal(SIGSEGV, SIGSEGV_Handler); |
| 169 | + int *p; |
| 170 | + *p = 10; |
| 171 | +} |
104 | 172 | ```
|
105 |
| -raising the signal: |
| 173 | + |
| 174 | + |
| 175 | +# Raising a Signal |
| 176 | +The `<csignal>` header file declared the function `raise()` to handle a particular signal. |
| 177 | +Syntax: |
106 | 178 | ```cpp
|
107 |
| -std::cout << "Before called Signal = " << s_value << std::endl; |
108 |
| -raise(SIGTERM); |
109 |
| -std::cout << "After called Signal = " << s_value << std::endl; |
| 179 | +int raise ( int signal_ ) |
| 180 | +``` |
| 181 | +
|
| 182 | +complete example: |
| 183 | +
|
| 184 | +``` |
| 185 | +sig_atomic_t s_value = 0; |
| 186 | +void SIGTERM_Handler(int signum) { s_value = signum; } |
| 187 | + |
| 188 | +int main() { |
| 189 | + signal(SIGTERM, SIGTERM_Handler); |
| 190 | + std::cout << "Before called Signal = " << s_value << std::endl; |
| 191 | + raise(SIGTERM); |
| 192 | + std::cout << "After called Signal = " << s_value << std::endl; |
| 193 | +} |
| 194 | + |
110 | 195 | ```
|
111 |
| - |
112 |
| - |
113 |
| - |
114 | 196 | [code](../src/signals.cpp)
|
0 commit comments