16e75ec5eSBalázs Kéri // 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*b4d9ac8bSUtkarsh Saxena // FIXME: Fix the checker to work in C++17 or later mode.
36e75ec5eSBalázs Kéri #include "stdcpp.h"
46e75ec5eSBalázs Kéri #include "stdio.h"
56e75ec5eSBalázs Kéri
66e75ec5eSBalázs Kéri // Functions called "signal" that are different from the system version.
76e75ec5eSBalázs Kéri typedef void (*callback_t)(int);
86e75ec5eSBalázs Kéri void signal(int, callback_t, int);
96e75ec5eSBalázs Kéri namespace ns {
106e75ec5eSBalázs Kéri void signal(int, callback_t);
116e75ec5eSBalázs Kéri }
126e75ec5eSBalázs Kéri
handler_unsafe(int)136e75ec5eSBalázs Kéri extern "C" void handler_unsafe(int) {
146e75ec5eSBalázs Kéri printf("xxx");
156e75ec5eSBalázs Kéri }
166e75ec5eSBalázs Kéri
handler_unsafe_1(int)176e75ec5eSBalázs Kéri extern "C" void handler_unsafe_1(int) {
186e75ec5eSBalázs Kéri printf("xxx");
196e75ec5eSBalázs Kéri }
206e75ec5eSBalázs Kéri
216e75ec5eSBalázs Kéri namespace test_invalid_handler {
226e75ec5eSBalázs Kéri
handler_non_extern_c(int)236e75ec5eSBalázs Kéri void handler_non_extern_c(int) {
246e75ec5eSBalázs Kéri printf("xxx");
256e75ec5eSBalázs Kéri }
266e75ec5eSBalázs Kéri
276e75ec5eSBalázs Kéri struct A {
handler_membertest_invalid_handler::A286e75ec5eSBalázs Kéri static void handler_member(int) {
296e75ec5eSBalázs Kéri printf("xxx");
306e75ec5eSBalázs Kéri }
316e75ec5eSBalázs Kéri };
326e75ec5eSBalázs Kéri
test()336e75ec5eSBalázs Kéri void test() {
346e75ec5eSBalázs Kéri std::signal(SIGINT, handler_unsafe_1);
356e75ec5eSBalázs Kéri // 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]
366e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:23: note: function 'handler_unsafe_1' registered here as signal handler
376e75ec5eSBalázs Kéri
386e75ec5eSBalázs Kéri std::signal(SIGINT, handler_non_extern_c);
396e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: functions without C linkage are not allowed as signal handler (until C++17) [bugprone-signal-handler]
406e75ec5eSBalázs Kéri std::signal(SIGINT, A::handler_member);
416e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: functions without C linkage are not allowed as signal handler (until C++17) [bugprone-signal-handler]
426e75ec5eSBalázs Kéri std::signal(SIGINT, [](int) { printf("xxx"); });
436e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: lambda function is not allowed as signal handler (until C++17) [bugprone-signal-handler]
446e75ec5eSBalázs Kéri
456e75ec5eSBalázs Kéri // This case is (deliberately) not found by the checker.
466e75ec5eSBalázs Kéri std::signal(SIGINT, [](int) -> callback_t { return &handler_unsafe; }(1));
476e75ec5eSBalázs Kéri }
486e75ec5eSBalázs Kéri
496e75ec5eSBalázs Kéri } // namespace test_invalid_handler
506e75ec5eSBalázs Kéri
516e75ec5eSBalázs Kéri namespace test_non_standard_signal_call {
526e75ec5eSBalázs Kéri
536e75ec5eSBalázs Kéri struct Signal {
546e75ec5eSBalázs Kéri static void signal(int, callback_t);
556e75ec5eSBalázs Kéri };
566e75ec5eSBalázs Kéri
test()576e75ec5eSBalázs Kéri void test() {
586e75ec5eSBalázs Kéri // No diagnostics here. All these signal calls differ from the standard system one.
596e75ec5eSBalázs Kéri signal(SIGINT, handler_unsafe, 1);
606e75ec5eSBalázs Kéri ns::signal(SIGINT, handler_unsafe);
616e75ec5eSBalázs Kéri Signal::signal(SIGINT, handler_unsafe);
626e75ec5eSBalázs Kéri system_other::signal(SIGINT, handler_unsafe);
636e75ec5eSBalázs Kéri }
646e75ec5eSBalázs Kéri
656e75ec5eSBalázs Kéri } // namespace test_non_standard_signal_call
666e75ec5eSBalázs Kéri
676e75ec5eSBalázs Kéri namespace test_cpp_construct_in_handler {
686e75ec5eSBalázs Kéri
696e75ec5eSBalázs Kéri struct Struct {
~Structtest_cpp_construct_in_handler::Struct706e75ec5eSBalázs Kéri virtual ~Struct() {}
716e75ec5eSBalázs Kéri void f1();
726e75ec5eSBalázs Kéri int *begin();
736e75ec5eSBalázs Kéri int *end();
746e75ec5eSBalázs Kéri static void f2();
756e75ec5eSBalázs Kéri };
766e75ec5eSBalázs Kéri struct Derived : public Struct {
776e75ec5eSBalázs Kéri };
786e75ec5eSBalázs Kéri
796e75ec5eSBalázs Kéri struct X {
806e75ec5eSBalázs Kéri X(int, float);
816e75ec5eSBalázs Kéri };
826e75ec5eSBalázs Kéri
836e75ec5eSBalázs Kéri Struct *S_Global;
846e75ec5eSBalázs Kéri const Struct *S_GlobalConst;
856e75ec5eSBalázs Kéri
f_non_extern_c()866e75ec5eSBalázs Kéri void f_non_extern_c() {
876e75ec5eSBalázs Kéri }
886e75ec5eSBalázs Kéri
f_default_arg(int P1=0)896e75ec5eSBalázs Kéri void f_default_arg(int P1 = 0) {
906e75ec5eSBalázs Kéri }
916e75ec5eSBalázs Kéri
handler_cpp(int)926e75ec5eSBalázs Kéri extern "C" void handler_cpp(int) {
936e75ec5eSBalázs Kéri using namespace ::test_cpp_construct_in_handler;
946e75ec5eSBalázs Kéri
956e75ec5eSBalázs Kéri // These calls are not found as problems.
966e75ec5eSBalázs Kéri // (Called functions are not analyzed if the current function has already
976e75ec5eSBalázs Kéri // other problems.)
986e75ec5eSBalázs Kéri f_non_extern_c();
996e75ec5eSBalázs Kéri Struct::f2();
1006e75ec5eSBalázs Kéri // 'auto' is not disallowed
1016e75ec5eSBalázs Kéri auto Auto = 28u;
1026e75ec5eSBalázs Kéri
1036e75ec5eSBalázs Kéri Struct S;
1046e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1056e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:10: remark: internally, the statement is parsed as a 'CXXConstructExpr'
1066e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1076e75ec5eSBalázs Kéri S_Global->f1();
1086e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1096e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXMemberCallExpr'
1106e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1116e75ec5eSBalázs Kéri const Struct &SRef = Struct();
1126e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1136e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:24: remark: internally, the statement is parsed as a 'CXXBindTemporaryExpr'
1146e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1156e75ec5eSBalázs Kéri X(3, 4.4);
1166e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1176e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXTemporaryObjectExpr'
1186e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1196e75ec5eSBalázs Kéri
1206e75ec5eSBalázs Kéri auto L = [](int i) { printf("%d", i); };
1216e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1226e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:12: remark: internally, the statement is parsed as a 'CXXConstructExpr'
1236e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1246e75ec5eSBalázs Kéri L(2);
1256e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1266e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXOperatorCallExpr'
1276e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1286e75ec5eSBalázs Kéri
1296e75ec5eSBalázs Kéri try {
1306e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1316e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXTryStmt'
1326e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1336e75ec5eSBalázs Kéri int A;
1346e75ec5eSBalázs Kéri } catch (int) {
1356e75ec5eSBalázs Kéri };
1366e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1376e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-3]]:5: remark: internally, the statement is parsed as a 'CXXCatchStmt'
1386e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1396e75ec5eSBalázs Kéri
1406e75ec5eSBalázs Kéri throw(12);
1416e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1426e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXThrowExpr'
1436e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1446e75ec5eSBalázs Kéri
1456e75ec5eSBalázs Kéri for (int I : S) {
1466e75ec5eSBalázs Kéri }
1476e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1486e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-3]]:3: remark: internally, the statement is parsed as a 'CXXForRangeStmt'
1496e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1506e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-5]]:14: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1516e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-6]]:14: remark: internally, the statement is parsed as a 'CXXMemberCallExpr'
1526e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1536e75ec5eSBalázs Kéri
1546e75ec5eSBalázs Kéri int Int = *(reinterpret_cast<int *>(&S));
1556e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1566e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:15: remark: internally, the statement is parsed as a 'CXXReinterpretCastExpr'
1576e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1586e75ec5eSBalázs Kéri Int = static_cast<int>(12.34);
1596e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1606e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:9: remark: internally, the statement is parsed as a 'CXXStaticCastExpr'
1616e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1626e75ec5eSBalázs Kéri Derived *Der = dynamic_cast<Derived *>(S_Global);
1636e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1646e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:18: remark: internally, the statement is parsed as a 'CXXDynamicCastExpr'
1656e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1666e75ec5eSBalázs Kéri Struct *SPtr = const_cast<Struct *>(S_GlobalConst);
1676e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1686e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:18: remark: internally, the statement is parsed as a 'CXXConstCastExpr'
1696e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1706e75ec5eSBalázs Kéri Int = int(12.34);
1716e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1726e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:9: remark: internally, the statement is parsed as a 'CXXFunctionalCastExpr'
1736e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1746e75ec5eSBalázs Kéri
1756e75ec5eSBalázs Kéri int *IPtr = new int[10];
1766e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1776e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:15: remark: internally, the statement is parsed as a 'CXXNewExpr'
1786e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1796e75ec5eSBalázs Kéri delete[] IPtr;
1806e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1816e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXDeleteExpr'
1826e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1836e75ec5eSBalázs Kéri IPtr = nullptr;
1846e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1856e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:10: remark: internally, the statement is parsed as a 'CXXNullPtrLiteralExpr'
1866e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1876e75ec5eSBalázs Kéri bool Bool = true;
1886e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1896e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:15: remark: internally, the statement is parsed as a 'CXXBoolLiteralExpr'
1906e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1916e75ec5eSBalázs Kéri f_default_arg();
1926e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
1936e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXDefaultArgExpr'
1946e75ec5eSBalázs Kéri // CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
1956e75ec5eSBalázs Kéri }
1966e75ec5eSBalázs Kéri
test()1976e75ec5eSBalázs Kéri void test() {
1986e75ec5eSBalázs Kéri std::signal(SIGINT, handler_cpp);
1996e75ec5eSBalázs Kéri }
2006e75ec5eSBalázs Kéri
2016e75ec5eSBalázs Kéri } // namespace test_cpp_construct_in_handler
2026e75ec5eSBalázs Kéri
2036e75ec5eSBalázs Kéri namespace test_cpp_indirect {
2046e75ec5eSBalázs Kéri
non_extern_c()2056e75ec5eSBalázs Kéri void non_extern_c() {
2066e75ec5eSBalázs Kéri int *P = nullptr;
2076e75ec5eSBalázs Kéri }
2086e75ec5eSBalázs Kéri
call_cpp_indirect()2096e75ec5eSBalázs Kéri extern "C" void call_cpp_indirect() {
2106e75ec5eSBalázs Kéri int *P = nullptr;
2116e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
2126e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-2]]:12: remark: internally, the statement is parsed as a 'CXXNullPtrLiteralExpr'
2136e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE+8]]:3: note: function 'call_cpp_indirect' called here from 'handler_cpp_indirect'
2146e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE+11]]:23: note: function 'handler_cpp_indirect' registered here as signal handler
2156e75ec5eSBalázs Kéri }
2166e75ec5eSBalázs Kéri
handler_cpp_indirect(int)2176e75ec5eSBalázs Kéri extern "C" void handler_cpp_indirect(int) {
2186e75ec5eSBalázs Kéri non_extern_c();
2196e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: functions without C linkage are not allowed as signal handler (until C++17) [bugprone-signal-handler]
2206e75ec5eSBalázs Kéri // CHECK-MESSAGES: :[[@LINE+5]]:23: note: function 'handler_cpp_indirect' registered here as signal handler
2216e75ec5eSBalázs Kéri call_cpp_indirect();
2226e75ec5eSBalázs Kéri }
2236e75ec5eSBalázs Kéri
test()2246e75ec5eSBalázs Kéri void test() {
2256e75ec5eSBalázs Kéri std::signal(SIGINT, handler_cpp_indirect);
2266e75ec5eSBalázs Kéri }
2276e75ec5eSBalázs Kéri
2286e75ec5eSBalázs Kéri } // namespace test_cpp_indirect
229