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
handler_unsafe(int)13 extern "C" void handler_unsafe(int) {
14 printf("xxx");
15 }
16
handler_unsafe_1(int)17 extern "C" void handler_unsafe_1(int) {
18 printf("xxx");
19 }
20
21 namespace test_invalid_handler {
22
handler_non_extern_c(int)23 void handler_non_extern_c(int) {
24 printf("xxx");
25 }
26
27 struct A {
handler_membertest_invalid_handler::A28 static void handler_member(int) {
29 printf("xxx");
30 }
31 };
32
test()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
test()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 {
~Structtest_cpp_construct_in_handler::Struct70 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
f_non_extern_c()86 void f_non_extern_c() {
87 }
88
f_default_arg(int P1=0)89 void f_default_arg(int P1 = 0) {
90 }
91
handler_cpp(int)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("%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
test()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
non_extern_c()205 void non_extern_c() {
206 int *P = nullptr;
207 }
208
call_cpp_indirect()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
handler_cpp_indirect(int)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
test()224 void test() {
225 std::signal(SIGINT, handler_cpp_indirect);
226 }
227
228 } // namespace test_cpp_indirect
229