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 
handler_printf(int)18 void handler_printf(int) {
19   printf("1234");
20   // 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]
21   // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'handler_printf'
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-2]]:3: note: function 'f_extern' called here from 'handler_extern'
33   // CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_extern' registered here as signal handler
34 }
35 
test_extern(void)36 void test_extern(void) {
37   signal(SIGINT, handler_extern);
38 }
39 
f_ok(void)40 void f_ok(void) {
41   abort();
42 }
43 
handler_ok(int)44 void handler_ok(int) {
45   f_ok();
46 }
47 
test_ok(void)48 void test_ok(void) {
49   signal(SIGINT, handler_ok);
50 }
51 
f_bad(void)52 void f_bad(void) {
53   printf("1234");
54   // 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]
55   // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_bad'
56   // CHECK-NOTES: :[[@LINE+5]]:3: note: function 'f_bad' called here from 'handler_bad'
57   // CHECK-NOTES: :[[@LINE+8]]:18: note: function 'handler_bad' registered here as signal handler
58 }
59 
handler_bad(int)60 void handler_bad(int) {
61   f_bad();
62 }
63 
test_bad(void)64 void test_bad(void) {
65   signal(SIGINT, handler_bad);
66 }
67 
f_bad1(void)68 void f_bad1(void) {
69   printf("1234");
70   // 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]
71   // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_bad1'
72   // CHECK-NOTES: :[[@LINE+6]]:3: note: function 'f_bad1' called here from 'f_bad2'
73   // CHECK-NOTES: :[[@LINE+9]]:3: note: function 'f_bad2' called here from 'handler_bad1'
74   // CHECK-NOTES: :[[@LINE+13]]:18: note: function 'handler_bad1' registered here as signal handler
75 }
76 
f_bad2(void)77 void f_bad2(void) {
78   f_bad1();
79 }
80 
handler_bad1(int)81 void handler_bad1(int) {
82   f_bad2();
83   f_bad1();
84 }
85 
test_bad1(void)86 void test_bad1(void) {
87   signal(SIGINT, handler_bad1);
88 }
89 
handler_abort(int)90 void handler_abort(int) {
91   abort();
92 }
93 
handler_signal(int)94 void handler_signal(int) {
95   // FIXME: It is only OK to call signal with the current signal number.
96   signal(0, SIG_DFL);
97 }
98 
handler_false_condition(int)99 void handler_false_condition(int) {
100   if (0)
101     printf("1234");
102   // 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]
103   // CHECK-NOTES: :[[@LINE-2]]:5: note: function 'printf' called here from 'handler_false_condition'
104   // CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_false_condition' registered here as signal handler
105 }
106 
test_false_condition(void)107 void test_false_condition(void) {
108   signal(SIGINT, handler_false_condition);
109 }
110 
handler_multiple_calls(int)111 void handler_multiple_calls(int) {
112   f_extern();
113   // 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]
114   // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'f_extern' called here from 'handler_multiple_calls'
115   // CHECK-NOTES: :[[@LINE+10]]:18: note: function 'handler_multiple_calls' registered here as signal handler
116   printf("1234");
117   // 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]
118   // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'handler_multiple_calls'
119   // CHECK-NOTES: :[[@LINE+6]]:18: note: function 'handler_multiple_calls' registered here as signal handler
120   f_extern();
121   // first 'f_extern' call found only
122 }
123 
test_multiple_calls(void)124 void test_multiple_calls(void) {
125   signal(SIGINT, handler_multiple_calls);
126 }
127 
128 void f_recursive(void);
129 
handler_recursive(int)130 void handler_recursive(int) {
131   f_recursive();
132   printf("");
133   // first 'printf' call (in f_recursive) found only
134 }
135 
f_recursive(void)136 void f_recursive(void) {
137   f_extern();
138   // 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]
139   // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'f_extern' called here from 'f_recursive'
140   // CHECK-NOTES: :[[@LINE-9]]:3: note: function 'f_recursive' called here from 'handler_recursive'
141   // CHECK-NOTES: :[[@LINE+10]]:18: note: function 'handler_recursive' registered here as signal handler
142   printf("");
143   // 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]
144   // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_recursive'
145   // CHECK-NOTES: :[[@LINE-14]]:3: note: function 'f_recursive' called here from 'handler_recursive'
146   // CHECK-NOTES: :[[@LINE+5]]:18: note: function 'handler_recursive' registered here as signal handler
147   handler_recursive(2);
148 }
149 
test_recursive(void)150 void test_recursive(void) {
151   signal(SIGINT, handler_recursive);
152 }
153 
f_multiple_paths(void)154 void f_multiple_paths(void) {
155   printf("");
156   // 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]
157   // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_multiple_paths'
158   // CHECK-NOTES: :[[@LINE+5]]:3: note: function 'f_multiple_paths' called here from 'handler_multiple_paths'
159   // CHECK-NOTES: :[[@LINE+9]]:18: note: function 'handler_multiple_paths' registered here as signal handler
160 }
161 
handler_multiple_paths(int)162 void handler_multiple_paths(int) {
163   f_multiple_paths();
164   f_multiple_paths();
165 }
166 
test_multiple_paths(void)167 void test_multiple_paths(void) {
168   signal(SIGINT, handler_multiple_paths);
169 }
170 
handler_function_pointer(int)171 void handler_function_pointer(int) {
172   void (*fp)(void) = f_extern;
173   // Call with function pointer is not evalauted by the check.
174   (*fp)();
175 }
176 
test_function_pointer(void)177 void test_function_pointer(void) {
178   signal(SIGINT, handler_function_pointer);
179 }
180 
test_other(void)181 void test_other(void) {
182   signal(SIGINT, handler_abort);
183   signal(SIGINT, handler_signal);
184 
185   signal(SIGINT, _Exit);
186   signal(SIGINT, other_call);
187   // 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]
188   signal(SIGINT, f_extern);
189   // CHECK-NOTES: :[[@LINE-1]]:18: warning: cannot verify that external function 'f_extern' is asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler]
190 
191   signal(SIGINT, SIG_IGN);
192   signal(SIGINT, SIG_DFL);
193 }
194