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 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("xxx"); 15 } 16 17 extern "C" void handler_unsafe_1(int) { 18 printf("xxx"); 19 } 20 21 namespace test_invalid_handler { 22 23 void handler_non_extern_c(int) { 24 printf("xxx"); 25 } 26 27 struct A { 28 static void handler_member(int) { 29 printf("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("%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