1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright © 2023 Keith Packard
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials provided
16  *    with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include <signal.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdbool.h>
40 
41 #define HANDLER_NOT_CALLED      0
42 #define HANDLER_SUCCESS         1
43 #define HANDLER_FAILED          2
44 
45 static sig_atomic_t     handler_result;
46 static sig_atomic_t     handler_sig_expect;
47 static sig_atomic_t     handler_sig_received;
48 
49 static void
signal_handler(int sig)50 signal_handler(int sig)
51 {
52     handler_sig_received = sig;
53     if (sig == (int) handler_sig_expect)
54         handler_result = HANDLER_SUCCESS;
55     else
56         handler_result = HANDLER_FAILED;
57 }
58 
59 static const int test_signals[] = {
60     SIGABRT,
61     SIGFPE,
62     SIGILL,
63     SIGINT,
64     SIGSEGV,
65     SIGTERM,
66 };
67 
68 #define MODE_IGN        0
69 #define MODE_CATCH      1
70 #define MODE_MAX        2
71 
72 #define NTEST_SIG    (sizeof(test_signals)/sizeof(test_signals[0]))
73 
main(void)74 int main(void)
75 {
76     void (*old_func)(int);
77     void (*new_func)(int);
78     void (*prev_func)(int);
79     int ret;
80     unsigned u;
81     int fail = 0;
82     int mode;
83 
84     for (u = 0; u < NTEST_SIG; u++) {
85         int sig = test_signals[u];
86         prev_func = SIG_DFL;
87         for (mode = 0; mode < MODE_MAX; mode++) {
88             switch (mode) {
89             case MODE_IGN:
90                 new_func = SIG_IGN;
91                 break;
92             case MODE_CATCH:
93                 new_func = signal_handler;
94                 break;
95             }
96 
97             /* Set up the signal handler */
98             old_func = signal(sig, new_func);
99             if (old_func != SIG_DFL) {
100                 printf("signal %d: old_func was %p, not SIG_DFL\n",
101                        sig, old_func);
102                 fail = 1;
103             }
104 
105             /* Invoke the handler */
106             prev_func = new_func;
107             handler_result = HANDLER_NOT_CALLED;
108             handler_sig_expect = (sig_atomic_t) sig;
109 
110             ret = raise(sig);
111             if (ret != 0) {
112                 printf("signal %d: raise returned %d\n", sig, ret);
113                 fail = 1;
114             }
115 
116             /* Validate the results */
117             switch (mode) {
118             case MODE_IGN:
119                 if (handler_result != HANDLER_NOT_CALLED) {
120                     printf("signal %d: handler called with SIG_IGN\n", sig);
121                     fail = 1;
122                 }
123                 break;
124             case MODE_CATCH:
125                 switch (handler_result) {
126                 case HANDLER_NOT_CALLED:
127                     printf("signal %d: handler not called\n", sig);
128                     fail = 1;
129                     break;
130                 case HANDLER_SUCCESS:
131                     prev_func = SIG_DFL;
132                     break;
133                 case HANDLER_FAILED:
134                     printf("signal %d: handler failed, received signal %d\n",
135                            sig, (int) handler_sig_received);
136                     fail = 1;
137                     break;
138                 }
139                 break;
140             default:
141                 fail = 1;
142                 break;
143             }
144 
145             old_func = signal(sig, SIG_DFL);
146             if (old_func != prev_func) {
147                 printf("signal %d: after test, signal is %p expected %p\n",
148                        sig, old_func, prev_func);
149                 fail = 1;
150             }
151         }
152     }
153     exit(fail);
154 }
155