10 #include "clang/ASTMatchers/ASTMatchFinder.h"
11 #include "llvm/ADT/DepthFirstIterator.h"
12 #include "llvm/ADT/STLExtras.h"
17 "signal",
"abort",
"_Exit",
"quick_exit"};
226 bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind> {
227 static llvm::ArrayRef<std::pair<
230 static constexpr std::pair<
233 {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind::Minimal,
235 {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind::POSIX,
238 return makeArrayRef(Mapping);
249 bool isStandardFunction(
const FunctionDecl *FD) {
276 return FD->getASTContext().getSourceManager().isInSystemHeader(
277 FD->getCanonicalDecl()->getLocation());
284 Expr *findCallExpr(
const CallGraphNode *Caller,
const CallGraphNode *Callee) {
285 auto FoundCallee = llvm::find_if(
286 Caller->callees(), [Callee](
const CallGraphNode::CallRecord &Call) {
287 return Call.Callee == Callee;
289 assert(FoundCallee != Caller->end() &&
290 "Callee should be called from the caller function here.");
291 return FoundCallee->CallExpr;
297 return isStandardFunction(&Node);
300 SignalHandlerCheck::SignalHandlerCheck(StringRef
Name,
303 AsyncSafeFunctionSet(
305 ConformingFunctions(AsyncSafeFunctionSet ==
311 Options.
store(Opts,
"AsyncSafeFunctionSet", AsyncSafeFunctionSet);
315 const LangOptions &
LangOpts)
const {
324 auto SignalFunction = functionDecl(hasAnyName(
"::signal",
"::std::signal"),
325 parameterCountIs(2), isStandardFunction());
327 declRefExpr(hasDeclaration(functionDecl().bind(
"handler_decl")),
328 unless(isExpandedFromMacro(
"SIG_IGN")),
329 unless(isExpandedFromMacro(
"SIG_DFL")))
330 .bind(
"handler_expr");
332 callExpr(callee(SignalFunction), hasArgument(1, HandlerExpr))
333 .bind(
"register_call"),
338 const auto *HandlerDecl =
339 Result.Nodes.getNodeAs<FunctionDecl>(
"handler_decl");
340 const auto *HandlerExpr = Result.Nodes.getNodeAs<DeclRefExpr>(
"handler_expr");
341 assert(Result.Nodes.getNodeAs<CallExpr>(
"register_call") && HandlerDecl &&
342 HandlerExpr &&
"All of these should exist in a match here.");
344 if (CG.size() <= 1) {
348 CG.addToCallGraph(
const_cast<TranslationUnitDecl *
>(
349 HandlerDecl->getTranslationUnitDecl()));
350 assert(CG.size() > 1 &&
351 "There should be at least one function added to call graph.");
354 if (!HandlerDecl->hasBody()) {
355 (void)checkFunction(HandlerDecl, HandlerExpr);
362 CallGraphNode *HandlerNode = CG.getNode(HandlerDecl->getCanonicalDecl());
363 assert(HandlerNode &&
364 "Handler with body should be present in the call graph.");
366 for (
auto Itr = llvm::df_begin(HandlerNode), ItrE = llvm::df_end(HandlerNode);
367 Itr != ItrE; ++Itr) {
368 if (
const auto *CallF = dyn_cast<FunctionDecl>((*Itr)->getDecl())) {
369 unsigned int PathL = Itr.getPathLength();
370 const Expr *CallOrRef = (PathL == 1)
372 : findCallExpr(Itr.getPath(PathL - 2), *Itr);
373 if (checkFunction(CallF, CallOrRef))
374 reportHandlerChain(Itr, HandlerExpr);
379 bool SignalHandlerCheck::checkFunction(
const FunctionDecl *FD,
380 const Expr *CallOrRef) {
381 bool FunctionIsCalled = isa<CallExpr>(CallOrRef);
383 if (isStandardFunction(FD)) {
384 if (!isStandardFunctionAsyncSafe(FD)) {
385 diag(CallOrRef->getBeginLoc(),
"standard function %0 may not be "
386 "asynchronous-safe; "
387 "%select{using it as|calling it from}1 "
388 "a signal handler may be dangerous")
389 << FD << FunctionIsCalled;
395 if (!FD->hasBody()) {
396 diag(CallOrRef->getBeginLoc(),
"cannot verify that external function %0 is "
397 "asynchronous-safe; "
398 "%select{using it as|calling it from}1 "
399 "a signal handler may be dangerous")
400 << FD << FunctionIsCalled;
407 bool SignalHandlerCheck::isStandardFunctionAsyncSafe(
408 const FunctionDecl *FD)
const {
409 assert(isStandardFunction(FD));
411 const IdentifierInfo *II = FD->getIdentifier();
417 if (ConformingFunctions.count(II->getName()))
423 void SignalHandlerCheck::reportHandlerChain(
424 const llvm::df_iterator<clang::CallGraphNode *> &Itr,
425 const DeclRefExpr *HandlerRef) {
426 int CallLevel = Itr.getPathLength() - 2;
427 assert(CallLevel >= -1 &&
"Empty iterator?");
429 const CallGraphNode *Caller = Itr.getPath(CallLevel + 1), *Callee =
nullptr;
430 while (CallLevel >= 0) {
432 Caller = Itr.getPath(CallLevel);
433 const Expr *
CE = findCallExpr(Caller, Callee);
434 diag(
CE->getBeginLoc(),
"function %0 called here from %1",
436 << cast<FunctionDecl>(Callee->getDecl())
437 << cast<FunctionDecl>(Caller->getDecl());
441 diag(HandlerRef->getBeginLoc(),
442 "function %0 registered here as signal handler", DiagnosticIDs::Note)
443 << cast<FunctionDecl>(Caller->getDecl()) << HandlerRef->getSourceRange();