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.
7typedef void (*callback_t)(int);
8void signal(int, callback_t, int);
9namespace ns {
10void signal(int, callback_t);
11}
12
13extern "C" void handler_unsafe(int) {
14 printf(format: "xxx");
15}
16
17extern "C" void handler_unsafe_1(int) {
18 printf(format: "xxx");
19}
20
21namespace test_invalid_handler {
22
23void handler_non_extern_c(int) {
24 printf(format: "xxx");
25}
26
27struct A {
28 static void handler_member(int) {
29 printf(format: "xxx");
30 }
31};
32
33void 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
51namespace test_non_standard_signal_call {
52
53struct Signal {
54 static void signal(int, callback_t);
55};
56
57void 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
67namespace test_cpp_construct_in_handler {
68
69struct Struct {
70 virtual ~Struct() {}
71 void f1();
72 int *begin();
73 int *end();
74 static void f2();
75};
76struct Derived : public Struct {
77};
78
79struct X {
80 X(int, float);
81};
82
83Struct *S_Global;
84const Struct *S_GlobalConst;
85
86void f_non_extern_c() {
87}
88
89void f_default_arg(int P1 = 0) {
90}
91
92extern "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
197void test() {
198 std::signal(SIGINT, handler_cpp);
199}
200
201} // namespace test_cpp_construct_in_handler
202
203namespace test_cpp_indirect {
204
205void non_extern_c() {
206 int *P = nullptr;
207}
208
209extern "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
217extern "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
224void test() {
225 std::signal(SIGINT, handler_cpp_indirect);
226}
227
228} // namespace test_cpp_indirect
229

source code of clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.cpp