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