1 | // RUN: %check_clang_tidy -std=c++14 %s bugprone-signal-handler %t -- -- -isystem %clang_tidy_headers -isystem %S/Inputs/signal-handler -target x86_64-unknown-unknown |
2 | // FIXME: Fix the checker to work in C++17 or later mode. |
3 | #include "stdcpp.h" |
4 | #include "stdio.h" |
5 | |
6 | // Functions called "signal" that are different from the system version. |
7 | typedef void (*callback_t)(int); |
8 | void signal(int, callback_t, int); |
9 | namespace ns { |
10 | void signal(int, callback_t); |
11 | } |
12 | |
13 | extern "C" void handler_unsafe(int) { |
14 | printf(format: "xxx" ); |
15 | } |
16 | |
17 | extern "C" void handler_unsafe_1(int) { |
18 | printf(format: "xxx" ); |
19 | } |
20 | |
21 | namespace test_invalid_handler { |
22 | |
23 | void handler_non_extern_c(int) { |
24 | printf(format: "xxx" ); |
25 | } |
26 | |
27 | struct A { |
28 | static void handler_member(int) { |
29 | printf(format: "xxx" ); |
30 | } |
31 | }; |
32 | |
33 | void test() { |
34 | std::signal(SIGINT, handler_unsafe_1); |
35 | // CHECK-MESSAGES: :[[@LINE-17]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] |
36 | // CHECK-MESSAGES: :[[@LINE-2]]:23: note: function 'handler_unsafe_1' registered here as signal handler |
37 | |
38 | std::signal(SIGINT, handler_non_extern_c); |
39 | // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: functions without C linkage are not allowed as signal handler (until C++17) [bugprone-signal-handler] |
40 | std::signal(SIGINT, A::handler_member); |
41 | // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: functions without C linkage are not allowed as signal handler (until C++17) [bugprone-signal-handler] |
42 | std::signal(SIGINT, [](int) { printf("xxx" ); }); |
43 | // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: lambda function is not allowed as signal handler (until C++17) [bugprone-signal-handler] |
44 | |
45 | // This case is (deliberately) not found by the checker. |
46 | std::signal(SIGINT, [](int) -> callback_t { return &handler_unsafe; }(1)); |
47 | } |
48 | |
49 | } // namespace test_invalid_handler |
50 | |
51 | namespace test_non_standard_signal_call { |
52 | |
53 | struct Signal { |
54 | static void signal(int, callback_t); |
55 | }; |
56 | |
57 | void test() { |
58 | // No diagnostics here. All these signal calls differ from the standard system one. |
59 | signal(SIGINT, handler_unsafe, 1); |
60 | ns::signal(SIGINT, handler_unsafe); |
61 | Signal::signal(SIGINT, handler_unsafe); |
62 | system_other::signal(SIGINT, handler_unsafe); |
63 | } |
64 | |
65 | } // namespace test_non_standard_signal_call |
66 | |
67 | namespace test_cpp_construct_in_handler { |
68 | |
69 | struct Struct { |
70 | virtual ~Struct() {} |
71 | void f1(); |
72 | int *begin(); |
73 | int *end(); |
74 | static void f2(); |
75 | }; |
76 | struct Derived : public Struct { |
77 | }; |
78 | |
79 | struct X { |
80 | X(int, float); |
81 | }; |
82 | |
83 | Struct *S_Global; |
84 | const Struct *S_GlobalConst; |
85 | |
86 | void f_non_extern_c() { |
87 | } |
88 | |
89 | void f_default_arg(int P1 = 0) { |
90 | } |
91 | |
92 | extern "C" void handler_cpp(int) { |
93 | using namespace ::test_cpp_construct_in_handler; |
94 | |
95 | // These calls are not found as problems. |
96 | // (Called functions are not analyzed if the current function has already |
97 | // other problems.) |
98 | f_non_extern_c(); |
99 | Struct::f2(); |
100 | // 'auto' is not disallowed |
101 | auto Auto = 28u; |
102 | |
103 | Struct S; |
104 | // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
105 | // CHECK-MESSAGES: :[[@LINE-2]]:10: remark: internally, the statement is parsed as a 'CXXConstructExpr' |
106 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
107 | S_Global->f1(); |
108 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
109 | // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXMemberCallExpr' |
110 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
111 | const Struct &SRef = Struct(); |
112 | // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
113 | // CHECK-MESSAGES: :[[@LINE-2]]:24: remark: internally, the statement is parsed as a 'CXXBindTemporaryExpr' |
114 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
115 | X(3, 4.4); |
116 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
117 | // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXTemporaryObjectExpr' |
118 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
119 | |
120 | auto L = [](int i) { printf(format: "%d" , i); }; |
121 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
122 | // CHECK-MESSAGES: :[[@LINE-2]]:12: remark: internally, the statement is parsed as a 'CXXConstructExpr' |
123 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
124 | L(2); |
125 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
126 | // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXOperatorCallExpr' |
127 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
128 | |
129 | try { |
130 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
131 | // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXTryStmt' |
132 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
133 | int A; |
134 | } catch (int) { |
135 | }; |
136 | // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
137 | // CHECK-MESSAGES: :[[@LINE-3]]:5: remark: internally, the statement is parsed as a 'CXXCatchStmt' |
138 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
139 | |
140 | throw(12); |
141 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
142 | // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXThrowExpr' |
143 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
144 | |
145 | for (int I : S) { |
146 | } |
147 | // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
148 | // CHECK-MESSAGES: :[[@LINE-3]]:3: remark: internally, the statement is parsed as a 'CXXForRangeStmt' |
149 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
150 | // CHECK-MESSAGES: :[[@LINE-5]]:14: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
151 | // CHECK-MESSAGES: :[[@LINE-6]]:14: remark: internally, the statement is parsed as a 'CXXMemberCallExpr' |
152 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
153 | |
154 | int Int = *(reinterpret_cast<int *>(&S)); |
155 | // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
156 | // CHECK-MESSAGES: :[[@LINE-2]]:15: remark: internally, the statement is parsed as a 'CXXReinterpretCastExpr' |
157 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
158 | Int = static_cast<int>(12.34); |
159 | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
160 | // CHECK-MESSAGES: :[[@LINE-2]]:9: remark: internally, the statement is parsed as a 'CXXStaticCastExpr' |
161 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
162 | Derived *Der = dynamic_cast<Derived *>(S_Global); |
163 | // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
164 | // CHECK-MESSAGES: :[[@LINE-2]]:18: remark: internally, the statement is parsed as a 'CXXDynamicCastExpr' |
165 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
166 | Struct *SPtr = const_cast<Struct *>(S_GlobalConst); |
167 | // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
168 | // CHECK-MESSAGES: :[[@LINE-2]]:18: remark: internally, the statement is parsed as a 'CXXConstCastExpr' |
169 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
170 | Int = int(12.34); |
171 | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
172 | // CHECK-MESSAGES: :[[@LINE-2]]:9: remark: internally, the statement is parsed as a 'CXXFunctionalCastExpr' |
173 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
174 | |
175 | int *IPtr = new int[10]; |
176 | // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
177 | // CHECK-MESSAGES: :[[@LINE-2]]:15: remark: internally, the statement is parsed as a 'CXXNewExpr' |
178 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
179 | delete[] IPtr; |
180 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
181 | // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXDeleteExpr' |
182 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
183 | IPtr = nullptr; |
184 | // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
185 | // CHECK-MESSAGES: :[[@LINE-2]]:10: remark: internally, the statement is parsed as a 'CXXNullPtrLiteralExpr' |
186 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
187 | bool Bool = true; |
188 | // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
189 | // CHECK-MESSAGES: :[[@LINE-2]]:15: remark: internally, the statement is parsed as a 'CXXBoolLiteralExpr' |
190 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
191 | f_default_arg(); |
192 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
193 | // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXDefaultArgExpr' |
194 | // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler |
195 | } |
196 | |
197 | void test() { |
198 | std::signal(SIGINT, handler_cpp); |
199 | } |
200 | |
201 | } // namespace test_cpp_construct_in_handler |
202 | |
203 | namespace test_cpp_indirect { |
204 | |
205 | void non_extern_c() { |
206 | int *P = nullptr; |
207 | } |
208 | |
209 | extern "C" void call_cpp_indirect() { |
210 | int *P = nullptr; |
211 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler] |
212 | // CHECK-MESSAGES: :[[@LINE-2]]:12: remark: internally, the statement is parsed as a 'CXXNullPtrLiteralExpr' |
213 | // CHECK-MESSAGES: :[[@LINE+8]]:3: note: function 'call_cpp_indirect' called here from 'handler_cpp_indirect' |
214 | // CHECK-MESSAGES: :[[@LINE+11]]:23: note: function 'handler_cpp_indirect' registered here as signal handler |
215 | } |
216 | |
217 | extern "C" void handler_cpp_indirect(int) { |
218 | non_extern_c(); |
219 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: functions without C linkage are not allowed as signal handler (until C++17) [bugprone-signal-handler] |
220 | // CHECK-MESSAGES: :[[@LINE+5]]:23: note: function 'handler_cpp_indirect' registered here as signal handler |
221 | call_cpp_indirect(); |
222 | } |
223 | |
224 | void test() { |
225 | std::signal(SIGINT, handler_cpp_indirect); |
226 | } |
227 | |
228 | } // namespace test_cpp_indirect |
229 | |