xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.c (revision 6e75ec5e38dacb14c9ac9578c8e07548861b6d27)
1 // RUN: %check_clang_tidy %s bugprone-signal-handler %t -- -- -isystem %clang_tidy_headers
2 
3 #include "signal.h"
4 #include "stdlib.h"
5 #include "stdio.h"
6 #include "system-other.h"
7 
8 // The function should be classified as standard function even if there is
9 // declaration the in source file.
10 // FIXME: The detection works only if the first declaration is in system
11 // header.
12 int printf(const char *, ...);
13 typedef void (*sighandler_t)(int);
14 sighandler_t signal(int signum, sighandler_t handler);
15 
16 void f_extern(void);
17 void f_extern_handler(int);
18 
handler_printf(int)19 void handler_printf(int) {
20   printf("1234");
21   // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
22   // CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_printf' registered here as signal handler
23 }
24 
test_printf(void)25 void test_printf(void) {
26   signal(SIGINT, handler_printf);
27 }
28 
handler_extern(int)29 void handler_extern(int) {
30   f_extern();
31   // CHECK-NOTES: :[[@LINE-1]]:3: warning: cannot verify that external function 'f_extern' is asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
32   // CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_extern' registered here as signal handler
33 }
34 
test_extern(void)35 void test_extern(void) {
36   signal(SIGINT, handler_extern);
37 }
38 
f_ok(void)39 void f_ok(void) {
40   abort();
41 }
42 
handler_ok(int)43 void handler_ok(int) {
44   f_ok();
45 }
46 
test_ok(void)47 void test_ok(void) {
48   signal(SIGINT, handler_ok);
49 }
50 
f_bad(void)51 void f_bad(void) {
52   printf("1234");
53   // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
54   // CHECK-NOTES: :[[@LINE+5]]:3: note: function 'f_bad' called here from 'handler_bad'
55   // CHECK-NOTES: :[[@LINE+8]]:18: note: function 'handler_bad' registered here as signal handler
56 }
57 
handler_bad(int)58 void handler_bad(int) {
59   f_bad();
60 }
61 
test_bad(void)62 void test_bad(void) {
63   signal(SIGINT, handler_bad);
64 }
65 
f_bad1(void)66 void f_bad1(void) {
67   printf("1234");
68   // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
69   // CHECK-NOTES: :[[@LINE+6]]:3: note: function 'f_bad1' called here from 'f_bad2'
70   // CHECK-NOTES: :[[@LINE+9]]:3: note: function 'f_bad2' called here from 'handler_bad1'
71   // CHECK-NOTES: :[[@LINE+13]]:18: note: function 'handler_bad1' registered here as signal handler
72 }
73 
f_bad2(void)74 void f_bad2(void) {
75   f_bad1();
76 }
77 
handler_bad1(int)78 void handler_bad1(int) {
79   f_bad2();
80   f_bad1();
81 }
82 
test_bad1(void)83 void test_bad1(void) {
84   signal(SIGINT, handler_bad1);
85 }
86 
handler_abort(int)87 void handler_abort(int) {
88   abort();
89 }
90 
handler_signal(int)91 void handler_signal(int) {
92   // FIXME: It is only OK to call signal with the current signal number.
93   signal(0, SIG_DFL);
94 }
95 
handler_false_condition(int)96 void handler_false_condition(int) {
97   if (0)
98     printf("1234");
99   // CHECK-NOTES: :[[@LINE-1]]:5: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
100   // CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_false_condition' registered here as signal handler
101 }
102 
test_false_condition(void)103 void test_false_condition(void) {
104   signal(SIGINT, handler_false_condition);
105 }
106 
handler_multiple_calls(int)107 void handler_multiple_calls(int) {
108   f_extern();
109   // CHECK-NOTES: :[[@LINE-1]]:3: warning: cannot verify that external function 'f_extern' is asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
110   // CHECK-NOTES: :[[@LINE+9]]:18: note: function 'handler_multiple_calls' registered here as signal handler
111   printf("1234");
112   // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
113   // CHECK-NOTES: :[[@LINE+6]]:18: note: function 'handler_multiple_calls' registered here as signal handler
114   f_extern();
115   // first 'f_extern' call found only
116 }
117 
test_multiple_calls(void)118 void test_multiple_calls(void) {
119   signal(SIGINT, handler_multiple_calls);
120 }
121 
122 void f_recursive(void);
123 
handler_recursive(int)124 void handler_recursive(int) {
125   f_recursive();
126   printf("");
127   // first 'printf' call (in f_recursive) found only
128 }
129 
f_recursive(void)130 void f_recursive(void) {
131   f_extern();
132   // CHECK-NOTES: :[[@LINE-1]]:3: warning: cannot verify that external function 'f_extern' is asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
133   // CHECK-NOTES: :[[@LINE-8]]:3: note: function 'f_recursive' called here from 'handler_recursive'
134   // CHECK-NOTES: :[[@LINE+9]]:18: note: function 'handler_recursive' registered here as signal handler
135   printf("");
136   // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
137   // CHECK-NOTES: :[[@LINE-12]]:3: note: function 'f_recursive' called here from 'handler_recursive'
138   // CHECK-NOTES: :[[@LINE+5]]:18: note: function 'handler_recursive' registered here as signal handler
139   handler_recursive(2);
140 }
141 
test_recursive(void)142 void test_recursive(void) {
143   signal(SIGINT, handler_recursive);
144 }
145 
f_multiple_paths(void)146 void f_multiple_paths(void) {
147   printf("");
148   // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
149   // CHECK-NOTES: :[[@LINE+5]]:3: note: function 'f_multiple_paths' called here from 'handler_multiple_paths'
150   // CHECK-NOTES: :[[@LINE+9]]:18: note: function 'handler_multiple_paths' registered here as signal handler
151 }
152 
handler_multiple_paths(int)153 void handler_multiple_paths(int) {
154   f_multiple_paths();
155   f_multiple_paths();
156 }
157 
test_multiple_paths(void)158 void test_multiple_paths(void) {
159   signal(SIGINT, handler_multiple_paths);
160 }
161 
handler_function_pointer(int)162 void handler_function_pointer(int) {
163   void (*fp)(void) = f_extern;
164   // Call with function pointer is not evalauted by the check.
165   (*fp)();
166 }
167 
test_function_pointer(void)168 void test_function_pointer(void) {
169   signal(SIGINT, handler_function_pointer);
170 }
171 
test_other(void)172 void test_other(void) {
173   signal(SIGINT, handler_abort);
174   signal(SIGINT, handler_signal);
175 
176   signal(SIGINT, _Exit);
177   signal(SIGINT, other_call);
178   // CHECK-NOTES: :[[@LINE-1]]:18: warning: standard function 'other_call' may not be asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler]
179   signal(SIGINT, f_extern_handler);
180   // CHECK-NOTES: :[[@LINE-1]]:18: warning: cannot verify that external function 'f_extern_handler' is asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler]
181 
182   signal(SIGINT, SIG_IGN);
183   signal(SIGINT, SIG_DFL);
184 }
185