xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.cpp (revision b4d9ac8b453e20e4223b5935c700698608a6425c)
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