1 //===--- SignalHandlerCheck.cpp - clang-tidy ------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SignalHandlerCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/RecursiveASTVisitor.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/Analysis/CallGraph.h" 14 #include "llvm/ADT/DenseSet.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/ADT/SmallVector.h" 17 #include <iterator> 18 #include <queue> 19 20 using namespace clang::ast_matchers; 21 22 namespace clang { 23 namespace tidy { 24 25 template <> 26 struct OptionEnumMapping< 27 bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType> { 28 static llvm::ArrayRef<std::pair< 29 bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType, StringRef>> 30 getEnumMapping() { 31 static constexpr std::pair< 32 bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType, StringRef> 33 Mapping[] = { 34 {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType::Minimal, 35 "minimal"}, 36 {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType::POSIX, 37 "POSIX"}, 38 }; 39 return makeArrayRef(Mapping); 40 } 41 }; 42 43 namespace bugprone { 44 45 static bool isSystemCall(const FunctionDecl *FD) { 46 // Find a possible redeclaration in system header. 47 // FIXME: Looking at the canonical declaration is not the most exact way 48 // to do this. 49 50 // Most common case will be inclusion directly from a header. 51 // This works fine by using canonical declaration. 52 // a.c 53 // #include <sysheader.h> 54 55 // Next most common case will be extern declaration. 56 // Can't catch this with either approach. 57 // b.c 58 // extern void sysfunc(void); 59 60 // Canonical declaration is the first found declaration, so this works. 61 // c.c 62 // #include <sysheader.h> 63 // extern void sysfunc(void); // redecl won't matter 64 65 // This does not work with canonical declaration. 66 // Probably this is not a frequently used case but may happen (the first 67 // declaration can be in a non-system header for example). 68 // d.c 69 // extern void sysfunc(void); // Canonical declaration, not in system header. 70 // #include <sysheader.h> 71 72 return FD->getASTContext().getSourceManager().isInSystemHeader( 73 FD->getCanonicalDecl()->getLocation()); 74 } 75 76 AST_MATCHER(FunctionDecl, isSystemCall) { return isSystemCall(&Node); } 77 78 SignalHandlerCheck::SignalHandlerCheck(StringRef Name, 79 ClangTidyContext *Context) 80 : ClangTidyCheck(Name, Context), 81 AsyncSafeFunctionSet( 82 Options.get("AsyncSafeFunctionSet", AsyncSafeFunctionSetType::POSIX)), 83 ConformingFunctions(AsyncSafeFunctionSet == 84 AsyncSafeFunctionSetType::Minimal 85 ? MinimalConformingFunctions 86 : POSIXConformingFunctions) {} 87 88 void SignalHandlerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { 89 Options.store(Opts, "AsyncSafeFunctionSet", AsyncSafeFunctionSet); 90 } 91 92 bool SignalHandlerCheck::isLanguageVersionSupported( 93 const LangOptions &LangOpts) const { 94 // FIXME: Make the checker useful on C++ code. 95 if (LangOpts.CPlusPlus) 96 return false; 97 98 return true; 99 } 100 101 void SignalHandlerCheck::registerMatchers(MatchFinder *Finder) { 102 auto SignalFunction = functionDecl(hasAnyName("::signal", "::std::signal"), 103 parameterCountIs(2), isSystemCall()); 104 auto HandlerExpr = 105 declRefExpr(hasDeclaration(functionDecl().bind("handler_decl")), 106 unless(isExpandedFromMacro("SIG_IGN")), 107 unless(isExpandedFromMacro("SIG_DFL"))) 108 .bind("handler_expr"); 109 Finder->addMatcher( 110 callExpr(callee(SignalFunction), hasArgument(1, HandlerExpr)) 111 .bind("register_call"), 112 this); 113 } 114 115 void SignalHandlerCheck::check(const MatchFinder::MatchResult &Result) { 116 const auto *SignalCall = Result.Nodes.getNodeAs<CallExpr>("register_call"); 117 const auto *HandlerDecl = 118 Result.Nodes.getNodeAs<FunctionDecl>("handler_decl"); 119 const auto *HandlerExpr = Result.Nodes.getNodeAs<DeclRefExpr>("handler_expr"); 120 121 // Visit each function encountered in the callgraph only once. 122 llvm::DenseSet<const FunctionDecl *> SeenFunctions; 123 124 // The worklist of the callgraph visitation algorithm. 125 std::deque<const CallExpr *> CalledFunctions; 126 127 auto ProcessFunction = [&](const FunctionDecl *F, const Expr *CallOrRef) { 128 // Ensure that canonical declaration is used. 129 F = F->getCanonicalDecl(); 130 131 // Do not visit function if already encountered. 132 if (!SeenFunctions.insert(F).second) 133 return true; 134 135 // Check if the call is allowed. 136 // Non-system calls are not considered. 137 if (isSystemCall(F)) { 138 if (isSystemCallAllowed(F)) 139 return true; 140 141 reportBug(F, CallOrRef, SignalCall, HandlerDecl); 142 143 return false; 144 } 145 146 // Get the body of the encountered non-system call function. 147 const FunctionDecl *FBody; 148 if (!F->hasBody(FBody)) { 149 reportBug(F, CallOrRef, SignalCall, HandlerDecl); 150 return false; 151 } 152 153 // Collect all called functions. 154 auto Matches = match(decl(forEachDescendant(callExpr().bind("call"))), 155 *FBody, FBody->getASTContext()); 156 for (const auto &Match : Matches) { 157 const auto *CE = Match.getNodeAs<CallExpr>("call"); 158 if (isa<FunctionDecl>(CE->getCalleeDecl())) 159 CalledFunctions.push_back(CE); 160 } 161 162 return true; 163 }; 164 165 if (!ProcessFunction(HandlerDecl, HandlerExpr)) 166 return; 167 168 // Visit the definition of every function referenced by the handler function. 169 // Check for allowed function calls. 170 while (!CalledFunctions.empty()) { 171 const CallExpr *FunctionCall = CalledFunctions.front(); 172 CalledFunctions.pop_front(); 173 // At insertion we have already ensured that only function calls are there. 174 const auto *F = cast<FunctionDecl>(FunctionCall->getCalleeDecl()); 175 176 if (!ProcessFunction(F, FunctionCall)) 177 break; 178 } 179 } 180 181 bool SignalHandlerCheck::isSystemCallAllowed(const FunctionDecl *FD) const { 182 const IdentifierInfo *II = FD->getIdentifier(); 183 // Unnamed functions are not explicitly allowed. 184 if (!II) 185 return false; 186 187 // FIXME: Improve for C++ (check for namespace). 188 if (ConformingFunctions.count(II->getName())) 189 return true; 190 191 return false; 192 } 193 194 void SignalHandlerCheck::reportBug(const FunctionDecl *CalledFunction, 195 const Expr *CallOrRef, 196 const CallExpr *SignalCall, 197 const FunctionDecl *HandlerDecl) { 198 diag(CallOrRef->getBeginLoc(), 199 "%0 may not be asynchronous-safe; " 200 "calling it from a signal handler may be dangerous") 201 << CalledFunction; 202 diag(SignalCall->getSourceRange().getBegin(), 203 "signal handler registered here", DiagnosticIDs::Note); 204 diag(HandlerDecl->getBeginLoc(), "handler function declared here", 205 DiagnosticIDs::Note); 206 } 207 208 // This is the minimal set of safe functions. 209 // https://wiki.sei.cmu.edu/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers 210 llvm::StringSet<> SignalHandlerCheck::MinimalConformingFunctions{ 211 "signal", "abort", "_Exit", "quick_exit"}; 212 213 // The POSIX-defined set of safe functions. 214 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03 215 // 'quick_exit' is added to the set additionally because it looks like the 216 // mentioned POSIX specification was not updated after 'quick_exit' appeared 217 // in the C11 standard. 218 // Also, we want to keep the "minimal set" a subset of the "POSIX set". 219 llvm::StringSet<> SignalHandlerCheck::POSIXConformingFunctions{ 220 "_Exit", 221 "_exit", 222 "abort", 223 "accept", 224 "access", 225 "aio_error", 226 "aio_return", 227 "aio_suspend", 228 "alarm", 229 "bind", 230 "cfgetispeed", 231 "cfgetospeed", 232 "cfsetispeed", 233 "cfsetospeed", 234 "chdir", 235 "chmod", 236 "chown", 237 "clock_gettime", 238 "close", 239 "connect", 240 "creat", 241 "dup", 242 "dup2", 243 "execl", 244 "execle", 245 "execv", 246 "execve", 247 "faccessat", 248 "fchdir", 249 "fchmod", 250 "fchmodat", 251 "fchown", 252 "fchownat", 253 "fcntl", 254 "fdatasync", 255 "fexecve", 256 "ffs", 257 "fork", 258 "fstat", 259 "fstatat", 260 "fsync", 261 "ftruncate", 262 "futimens", 263 "getegid", 264 "geteuid", 265 "getgid", 266 "getgroups", 267 "getpeername", 268 "getpgrp", 269 "getpid", 270 "getppid", 271 "getsockname", 272 "getsockopt", 273 "getuid", 274 "htonl", 275 "htons", 276 "kill", 277 "link", 278 "linkat", 279 "listen", 280 "longjmp", 281 "lseek", 282 "lstat", 283 "memccpy", 284 "memchr", 285 "memcmp", 286 "memcpy", 287 "memmove", 288 "memset", 289 "mkdir", 290 "mkdirat", 291 "mkfifo", 292 "mkfifoat", 293 "mknod", 294 "mknodat", 295 "ntohl", 296 "ntohs", 297 "open", 298 "openat", 299 "pause", 300 "pipe", 301 "poll", 302 "posix_trace_event", 303 "pselect", 304 "pthread_kill", 305 "pthread_self", 306 "pthread_sigmask", 307 "quick_exit", 308 "raise", 309 "read", 310 "readlink", 311 "readlinkat", 312 "recv", 313 "recvfrom", 314 "recvmsg", 315 "rename", 316 "renameat", 317 "rmdir", 318 "select", 319 "sem_post", 320 "send", 321 "sendmsg", 322 "sendto", 323 "setgid", 324 "setpgid", 325 "setsid", 326 "setsockopt", 327 "setuid", 328 "shutdown", 329 "sigaction", 330 "sigaddset", 331 "sigdelset", 332 "sigemptyset", 333 "sigfillset", 334 "sigismember", 335 "siglongjmp", 336 "signal", 337 "sigpause", 338 "sigpending", 339 "sigprocmask", 340 "sigqueue", 341 "sigset", 342 "sigsuspend", 343 "sleep", 344 "sockatmark", 345 "socket", 346 "socketpair", 347 "stat", 348 "stpcpy", 349 "stpncpy", 350 "strcat", 351 "strchr", 352 "strcmp", 353 "strcpy", 354 "strcspn", 355 "strlen", 356 "strncat", 357 "strncmp", 358 "strncpy", 359 "strnlen", 360 "strpbrk", 361 "strrchr", 362 "strspn", 363 "strstr", 364 "strtok_r", 365 "symlink", 366 "symlinkat", 367 "tcdrain", 368 "tcflow", 369 "tcflush", 370 "tcgetattr", 371 "tcgetpgrp", 372 "tcsendbreak", 373 "tcsetattr", 374 "tcsetpgrp", 375 "time", 376 "timer_getoverrun", 377 "timer_gettime", 378 "timer_settime", 379 "times", 380 "umask", 381 "uname", 382 "unlink", 383 "unlinkat", 384 "utime", 385 "utimensat", 386 "utimes", 387 "wait", 388 "waitpid", 389 "wcpcpy", 390 "wcpncpy", 391 "wcscat", 392 "wcschr", 393 "wcscmp", 394 "wcscpy", 395 "wcscspn", 396 "wcslen", 397 "wcsncat", 398 "wcsncmp", 399 "wcsncpy", 400 "wcsnlen", 401 "wcspbrk", 402 "wcsrchr", 403 "wcsspn", 404 "wcsstr", 405 "wcstok", 406 "wmemchr", 407 "wmemcmp", 408 "wmemcpy", 409 "wmemmove", 410 "wmemset", 411 "write"}; 412 413 } // namespace bugprone 414 } // namespace tidy 415 } // namespace clang 416