diff --git a/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.h b/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.h --- a/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.h @@ -24,7 +24,7 @@ /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-signal-handler-check.html class SignalHandlerCheck : public ClangTidyCheck { public: - enum class AsyncSafeFunctionSetType { Minimal, POSIX }; + enum class AsyncSafeFunctionSetKind { Minimal, POSIX }; SignalHandlerCheck(StringRef Name, ClangTidyContext *Context); void storeOptions(ClangTidyOptions::OptionMap &Opts) override; @@ -33,22 +33,34 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; private: - bool isFunctionAsyncSafe(const FunctionDecl *FD) const; - bool isSystemCallAsyncSafe(const FunctionDecl *FD) const; - void reportBug(const FunctionDecl *CalledFunction, const Expr *CallOrRef, - bool DirectHandler); - void reportHandlerCommon(llvm::df_iterator Itr, - const CallExpr *SignalCall, - const FunctionDecl *HandlerDecl, - const Expr *HandlerRef); + /// Check if a function is allowed as a signal handler. + /// Should test the properties of the function, and check in the code body. + /// Should not check function calls in the code (this part is done by the call + /// graph scan). + /// @param FD The function to check. It may or may not have a definition. + /// @param CallOrRef Location of the call to this function (in another + /// function) or the reference to the function (if it is used as a registered + /// signal handler). This is the location where diagnostics are to be placed. + /// @return Returns true if a diagnostic was emitted for this function. + bool checkFunction(const FunctionDecl *FD, const Expr *CallOrRef); + /// Returns true if a standard library function is considered as + /// asynchronous-safe. + bool isStandardFunctionAsyncSafe(const FunctionDecl *FD) const; + /// Add diagnostic notes to show the call chain of functions from a signal + /// handler to a function that is called (directly or indirectly) from it. + /// Also add a note to the place where the signal handler is registered. + /// @param Itr Position during a call graph depth-first iteration. It contains + /// the "path" (call chain) from the signal handler to the actual found + /// function call. + /// @param HandlerRef Reference to the signal handler function where it is + /// registered as signal handler. + void reportHandlerChain(const llvm::df_iterator &Itr, + const DeclRefExpr *HandlerRef); clang::CallGraph CG; - AsyncSafeFunctionSetType AsyncSafeFunctionSet; - llvm::StringSet<> &ConformingFunctions; - - static llvm::StringSet<> MinimalConformingFunctions; - static llvm::StringSet<> POSIXConformingFunctions; + AsyncSafeFunctionSetKind AsyncSafeFunctionSet; + const llvm::StringSet<> ConformingFunctions; }; } // namespace bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp @@ -11,215 +11,9 @@ #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/STLExtras.h" -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { - -template <> -struct OptionEnumMapping< - bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType> { - static llvm::ArrayRef> - getEnumMapping() { - static constexpr std::pair< - bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType, StringRef> - Mapping[] = { - {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType::Minimal, - "minimal"}, - {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType::POSIX, - "POSIX"}, - }; - return makeArrayRef(Mapping); - } -}; - -namespace bugprone { - -namespace { - -bool isSystemCall(const FunctionDecl *FD) { - // Find a possible redeclaration in system header. - // FIXME: Looking at the canonical declaration is not the most exact way - // to do this. - - // Most common case will be inclusion directly from a header. - // This works fine by using canonical declaration. - // a.c - // #include - - // Next most common case will be extern declaration. - // Can't catch this with either approach. - // b.c - // extern void sysfunc(void); - - // Canonical declaration is the first found declaration, so this works. - // c.c - // #include - // extern void sysfunc(void); // redecl won't matter - - // This does not work with canonical declaration. - // Probably this is not a frequently used case but may happen (the first - // declaration can be in a non-system header for example). - // d.c - // extern void sysfunc(void); // Canonical declaration, not in system header. - // #include - - return FD->getASTContext().getSourceManager().isInSystemHeader( - FD->getCanonicalDecl()->getLocation()); -} - -/// Given a call graph node of a function and another one that is called from -/// this function, get a CallExpr of the corresponding function call. -/// It is unspecified which call is found if multiple calls exist, but the order -/// should be deterministic (depend only on the AST). -Expr *findCallExpr(const CallGraphNode *Caller, const CallGraphNode *Callee) { - auto FoundCallee = llvm::find_if( - Caller->callees(), [Callee](const CallGraphNode::CallRecord &Call) { - return Call.Callee == Callee; - }); - assert(FoundCallee != Caller->end() && - "Callee should be called from the caller function here."); - return FoundCallee->CallExpr; -} - -} // namespace - -AST_MATCHER(FunctionDecl, isSystemCall) { return isSystemCall(&Node); } - -SignalHandlerCheck::SignalHandlerCheck(StringRef Name, - ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - AsyncSafeFunctionSet( - Options.get("AsyncSafeFunctionSet", AsyncSafeFunctionSetType::POSIX)), - ConformingFunctions(AsyncSafeFunctionSet == - AsyncSafeFunctionSetType::Minimal - ? MinimalConformingFunctions - : POSIXConformingFunctions) {} - -void SignalHandlerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "AsyncSafeFunctionSet", AsyncSafeFunctionSet); -} - -bool SignalHandlerCheck::isLanguageVersionSupported( - const LangOptions &LangOpts) const { - // FIXME: Make the checker useful on C++ code. - if (LangOpts.CPlusPlus) - return false; - - return true; -} - -void SignalHandlerCheck::registerMatchers(MatchFinder *Finder) { - auto SignalFunction = functionDecl(hasAnyName("::signal", "::std::signal"), - parameterCountIs(2), isSystemCall()); - auto HandlerExpr = - declRefExpr(hasDeclaration(functionDecl().bind("handler_decl")), - unless(isExpandedFromMacro("SIG_IGN")), - unless(isExpandedFromMacro("SIG_DFL"))) - .bind("handler_expr"); - Finder->addMatcher( - callExpr(callee(SignalFunction), hasArgument(1, HandlerExpr)) - .bind("register_call"), - this); -} - -void SignalHandlerCheck::check(const MatchFinder::MatchResult &Result) { - const auto *SignalCall = Result.Nodes.getNodeAs("register_call"); - const auto *HandlerDecl = - Result.Nodes.getNodeAs("handler_decl"); - const auto *HandlerExpr = Result.Nodes.getNodeAs("handler_expr"); - assert(SignalCall && HandlerDecl && HandlerExpr && - "All of these should exist in a match here."); - - if (CG.size() <= 1) { - // Call graph must be populated with the entire TU at the beginning. - // (It is possible to add a single function but the functions called from it - // are not analysed in this case.) - CG.addToCallGraph(const_cast( - HandlerDecl->getTranslationUnitDecl())); - assert(CG.size() > 1 && - "There should be at least one function added to call graph."); - } - - // Check for special case when the signal handler itself is an unsafe external - // function. - if (!isFunctionAsyncSafe(HandlerDecl)) { - reportBug(HandlerDecl, HandlerExpr, /*DirectHandler=*/true); - return; - } - - CallGraphNode *HandlerNode = CG.getNode(HandlerDecl); - // Signal handler can be external but not unsafe, no call graph in this case. - if (!HandlerNode) - return; - // Start from signal handler and visit every function call. - for (auto Itr = llvm::df_begin(HandlerNode), ItrE = llvm::df_end(HandlerNode); - Itr != ItrE; ++Itr) { - const auto *CallF = dyn_cast((*Itr)->getDecl()); - if (CallF && !isFunctionAsyncSafe(CallF)) { - assert(Itr.getPathLength() >= 2); - reportBug(CallF, findCallExpr(Itr.getPath(Itr.getPathLength() - 2), *Itr), - /*DirectHandler=*/false); - reportHandlerCommon(Itr, SignalCall, HandlerDecl, HandlerExpr); - } - } -} - -bool SignalHandlerCheck::isFunctionAsyncSafe(const FunctionDecl *FD) const { - if (isSystemCall(FD)) - return isSystemCallAsyncSafe(FD); - // For external (not checkable) functions assume that these are unsafe. - return FD->hasBody(); -} - -bool SignalHandlerCheck::isSystemCallAsyncSafe(const FunctionDecl *FD) const { - const IdentifierInfo *II = FD->getIdentifier(); - // Unnamed functions are not explicitly allowed. - if (!II) - return false; - - // FIXME: Improve for C++ (check for namespace). - if (ConformingFunctions.count(II->getName())) - return true; - - return false; -} - -void SignalHandlerCheck::reportBug(const FunctionDecl *CalledFunction, - const Expr *CallOrRef, bool DirectHandler) { - diag(CallOrRef->getBeginLoc(), - "%0 may not be asynchronous-safe; %select{calling it from|using it as}1 " - "a signal handler may be dangerous") - << CalledFunction << DirectHandler; -} - -void SignalHandlerCheck::reportHandlerCommon( - llvm::df_iterator Itr, const CallExpr *SignalCall, - const FunctionDecl *HandlerDecl, const Expr *HandlerRef) { - int CallLevel = Itr.getPathLength() - 2; - assert(CallLevel >= -1 && "Empty iterator?"); - - const CallGraphNode *Caller = Itr.getPath(CallLevel + 1), *Callee = nullptr; - while (CallLevel >= 0) { - Callee = Caller; - Caller = Itr.getPath(CallLevel); - const Expr *CE = findCallExpr(Caller, Callee); - diag(CE->getBeginLoc(), "function %0 called here from %1", - DiagnosticIDs::Note) - << cast(Callee->getDecl()) - << cast(Caller->getDecl()); - --CallLevel; - } - - diag(HandlerRef->getBeginLoc(), - "function %0 registered here as signal handler", DiagnosticIDs::Note) - << HandlerDecl; -} - // This is the minimal set of safe functions. // https://wiki.sei.cmu.edu/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers -llvm::StringSet<> SignalHandlerCheck::MinimalConformingFunctions{ +constexpr std::initializer_list MinimalConformingFunctions = { "signal", "abort", "_Exit", "quick_exit"}; // The POSIX-defined set of safe functions. @@ -228,7 +22,7 @@ // mentioned POSIX specification was not updated after 'quick_exit' appeared // in the C11 standard. // Also, we want to keep the "minimal set" a subset of the "POSIX set". -llvm::StringSet<> SignalHandlerCheck::POSIXConformingFunctions{ +constexpr std::initializer_list POSIXConformingFunctions = { "_Exit", "_exit", "abort", @@ -422,6 +216,234 @@ "wmemset", "write"}; +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +template <> +struct OptionEnumMapping< + bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind> { + static llvm::ArrayRef> + getEnumMapping() { + static constexpr std::pair< + bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind, StringRef> + Mapping[] = { + {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind::Minimal, + "minimal"}, + {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetKind::POSIX, + "POSIX"}, + }; + return makeArrayRef(Mapping); + } +}; + +namespace bugprone { + +namespace { + +/// Returns if a function is declared inside a system header. +/// These functions are considered to be "standard" (system-provided) library +/// functions. +bool isStandardFunction(const FunctionDecl *FD) { + // Find a possible redeclaration in system header. + // FIXME: Looking at the canonical declaration is not the most exact way + // to do this. + + // Most common case will be inclusion directly from a header. + // This works fine by using canonical declaration. + // a.c + // #include + + // Next most common case will be extern declaration. + // Can't catch this with either approach. + // b.c + // extern void sysfunc(void); + + // Canonical declaration is the first found declaration, so this works. + // c.c + // #include + // extern void sysfunc(void); // redecl won't matter + + // This does not work with canonical declaration. + // Probably this is not a frequently used case but may happen (the first + // declaration can be in a non-system header for example). + // d.c + // extern void sysfunc(void); // Canonical declaration, not in system header. + // #include + + return FD->getASTContext().getSourceManager().isInSystemHeader( + FD->getCanonicalDecl()->getLocation()); +} + +/// Given a call graph node of a \p Caller function and a \p Callee that is +/// called from \p Caller, get a \c CallExpr of the corresponding function call. +/// It is unspecified which call is found if multiple calls exist, but the order +/// should be deterministic (depend only on the AST). +Expr *findCallExpr(const CallGraphNode *Caller, const CallGraphNode *Callee) { + auto FoundCallee = llvm::find_if( + Caller->callees(), [Callee](const CallGraphNode::CallRecord &Call) { + return Call.Callee == Callee; + }); + assert(FoundCallee != Caller->end() && + "Callee should be called from the caller function here."); + return FoundCallee->CallExpr; +} + +} // namespace + +AST_MATCHER(FunctionDecl, isStandardFunction) { + return isStandardFunction(&Node); +} + +SignalHandlerCheck::SignalHandlerCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + AsyncSafeFunctionSet( + Options.get("AsyncSafeFunctionSet", AsyncSafeFunctionSetKind::POSIX)), + ConformingFunctions(AsyncSafeFunctionSet == + AsyncSafeFunctionSetKind::Minimal + ? MinimalConformingFunctions + : POSIXConformingFunctions) {} + +void SignalHandlerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "AsyncSafeFunctionSet", AsyncSafeFunctionSet); +} + +bool SignalHandlerCheck::isLanguageVersionSupported( + const LangOptions &LangOpts) const { + // FIXME: Make the checker useful on C++ code. + if (LangOpts.CPlusPlus) + return false; + + return true; +} + +void SignalHandlerCheck::registerMatchers(MatchFinder *Finder) { + auto SignalFunction = functionDecl(hasAnyName("::signal", "::std::signal"), + parameterCountIs(2), isStandardFunction()); + auto HandlerExpr = + declRefExpr(hasDeclaration(functionDecl().bind("handler_decl")), + unless(isExpandedFromMacro("SIG_IGN")), + unless(isExpandedFromMacro("SIG_DFL"))) + .bind("handler_expr"); + Finder->addMatcher( + callExpr(callee(SignalFunction), hasArgument(1, HandlerExpr)) + .bind("register_call"), + this); +} + +void SignalHandlerCheck::check(const MatchFinder::MatchResult &Result) { + const auto *SignalCall = Result.Nodes.getNodeAs("register_call"); + const auto *HandlerDecl = + Result.Nodes.getNodeAs("handler_decl"); + const auto *HandlerExpr = Result.Nodes.getNodeAs("handler_expr"); + assert(SignalCall && HandlerDecl && HandlerExpr && + "All of these should exist in a match here."); + + if (CG.size() <= 1) { + // Call graph must be populated with the entire TU at the beginning. + // (It is possible to add a single function but the functions called from it + // are not analysed in this case.) + CG.addToCallGraph(const_cast( + HandlerDecl->getTranslationUnitDecl())); + assert(CG.size() > 1 && + "There should be at least one function added to call graph."); + } + + if (!HandlerDecl->hasBody()) { + (void)checkFunction(HandlerDecl, HandlerExpr); + // Here checkFunction will put the messages to HandlerExpr. + // No need to show a call chain. + // Without code body there is nothing more to check. + return; + } + + CallGraphNode *HandlerNode = CG.getNode(HandlerDecl->getCanonicalDecl()); + assert(HandlerNode && + "Handler with body should be present in the call graph."); + // Start from signal handler and visit every function call. + for (auto Itr = llvm::df_begin(HandlerNode), ItrE = llvm::df_end(HandlerNode); + Itr != ItrE; ++Itr) { + if (const auto *CallF = dyn_cast((*Itr)->getDecl())) { + unsigned int PathL = Itr.getPathLength(); + const Expr *CallOrRef = (PathL == 1) + ? HandlerExpr + : findCallExpr(Itr.getPath(PathL - 2), *Itr); + if (checkFunction(CallF, CallOrRef)) + reportHandlerChain(Itr, HandlerExpr); + } + } +} + +bool SignalHandlerCheck::checkFunction(const FunctionDecl *FD, + const Expr *CallOrRef) { + bool FunctionIsCalled = isa(CallOrRef); + + if (isStandardFunction(FD)) { + if (!isStandardFunctionAsyncSafe(FD)) { + diag(CallOrRef->getBeginLoc(), "standard function %0 may not be " + "asynchronous-safe; " + "%select{using it as|calling it from}1 " + "a signal handler may be dangerous") + << FD << FunctionIsCalled; + return true; + } + return false; + } + + if (!FD->hasBody()) { + diag(CallOrRef->getBeginLoc(), "cannot verify that external function %0 is " + "asynchronous-safe; " + "%select{using it as|calling it from}1 " + "a signal handler may be dangerous") + << FD << FunctionIsCalled; + return true; + } + + return false; +} + +bool SignalHandlerCheck::isStandardFunctionAsyncSafe( + const FunctionDecl *FD) const { + assert(isStandardFunction(FD)); + + const IdentifierInfo *II = FD->getIdentifier(); + // Unnamed functions are not explicitly allowed. + if (!II) + return false; + + // FIXME: Improve for C++ (check for namespace). + if (ConformingFunctions.count(II->getName())) + return true; + + return false; +} + +void SignalHandlerCheck::reportHandlerChain( + const llvm::df_iterator &Itr, + const DeclRefExpr *HandlerRef) { + int CallLevel = Itr.getPathLength() - 2; + assert(CallLevel >= -1 && "Empty iterator?"); + + const CallGraphNode *Caller = Itr.getPath(CallLevel + 1), *Callee = nullptr; + while (CallLevel >= 0) { + Callee = Caller; + Caller = Itr.getPath(CallLevel); + const Expr *CE = findCallExpr(Caller, Callee); + diag(CE->getBeginLoc(), "function %0 called here from %1", + DiagnosticIDs::Note) + << cast(Callee->getDecl()) + << cast(Caller->getDecl()); + --CallLevel; + } + + diag(HandlerRef->getBeginLoc(), + "function %0 registered here as signal handler", DiagnosticIDs::Note) + << cast(Caller->getDecl()) << HandlerRef->getSourceRange(); +} + } // namespace bugprone } // namespace tidy } // namespace clang diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler-minimal.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler-minimal.c --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler-minimal.c +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler-minimal.c @@ -10,12 +10,12 @@ void handler_bad1(int) { _exit(0); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: '_exit' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: standard function '_exit' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] } void handler_bad2(void *dst, const void *src) { memcpy(dst, src, 10); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'memcpy' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: standard function 'memcpy' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] } void handler_good(int) { diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler-posix.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler-posix.c --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler-posix.c +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler-posix.c @@ -11,7 +11,7 @@ void handler_bad(int) { printf("1234"); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] } void handler_good(int) { diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler.c --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler.c +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-handler.c @@ -5,7 +5,7 @@ #include "stdio.h" #include "system-other.h" -// The function should be classified as system call even if there is +// The function should be classified as standard function even if there is // declaration the in source file. // FIXME: The detection works only if the first declaration is in system // header. @@ -17,7 +17,7 @@ void handler_printf(int) { printf("1234"); - // CHECK-NOTES: :[[@LINE-1]]:3: warning: 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'handler_printf' // CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_printf' registered here as signal handler } @@ -28,7 +28,7 @@ void handler_extern(int) { f_extern(); - // CHECK-NOTES: :[[@LINE-1]]:3: warning: 'f_extern' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:3: warning: cannot verify that external function 'f_extern' is asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'f_extern' called here from 'handler_extern' // CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_extern' registered here as signal handler } @@ -51,7 +51,7 @@ void f_bad(void) { printf("1234"); - // CHECK-NOTES: :[[@LINE-1]]:3: warning: 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_bad' // CHECK-NOTES: :[[@LINE+5]]:3: note: function 'f_bad' called here from 'handler_bad' // CHECK-NOTES: :[[@LINE+8]]:18: note: function 'handler_bad' registered here as signal handler @@ -67,7 +67,7 @@ void f_bad1(void) { printf("1234"); - // CHECK-NOTES: :[[@LINE-1]]:3: warning: 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_bad1' // CHECK-NOTES: :[[@LINE+6]]:3: note: function 'f_bad1' called here from 'f_bad2' // CHECK-NOTES: :[[@LINE+9]]:3: note: function 'f_bad2' called here from 'handler_bad1' @@ -99,7 +99,7 @@ void handler_false_condition(int) { if (0) printf("1234"); - // CHECK-NOTES: :[[@LINE-1]]:5: warning: 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:5: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:5: note: function 'printf' called here from 'handler_false_condition' // CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_false_condition' registered here as signal handler } @@ -110,11 +110,11 @@ void handler_multiple_calls(int) { f_extern(); - // CHECK-NOTES: :[[@LINE-1]]:3: warning: 'f_extern' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:3: warning: cannot verify that external function 'f_extern' is asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'f_extern' called here from 'handler_multiple_calls' // CHECK-NOTES: :[[@LINE+10]]:18: note: function 'handler_multiple_calls' registered here as signal handler printf("1234"); - // CHECK-NOTES: :[[@LINE-1]]:3: warning: 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'handler_multiple_calls' // CHECK-NOTES: :[[@LINE+6]]:18: note: function 'handler_multiple_calls' registered here as signal handler f_extern(); @@ -130,17 +130,17 @@ void handler_recursive(int) { f_recursive(); printf(""); - // first 'printf' call (in other function) found only + // first 'printf' call (in f_recursive) found only } void f_recursive(void) { f_extern(); - // CHECK-NOTES: :[[@LINE-1]]:3: warning: 'f_extern' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:3: warning: cannot verify that external function 'f_extern' is asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'f_extern' called here from 'f_recursive' // CHECK-NOTES: :[[@LINE-9]]:3: note: function 'f_recursive' called here from 'handler_recursive' // CHECK-NOTES: :[[@LINE+10]]:18: note: function 'handler_recursive' registered here as signal handler printf(""); - // CHECK-NOTES: :[[@LINE-1]]:3: warning: 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_recursive' // CHECK-NOTES: :[[@LINE-14]]:3: note: function 'f_recursive' called here from 'handler_recursive' // CHECK-NOTES: :[[@LINE+5]]:18: note: function 'handler_recursive' registered here as signal handler @@ -153,7 +153,7 @@ void f_multiple_paths(void) { printf(""); - // CHECK-NOTES: :[[@LINE-1]]:3: warning: 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler] // CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_multiple_paths' // CHECK-NOTES: :[[@LINE+5]]:3: note: function 'f_multiple_paths' called here from 'handler_multiple_paths' // CHECK-NOTES: :[[@LINE+9]]:18: note: function 'handler_multiple_paths' registered here as signal handler @@ -184,9 +184,9 @@ signal(SIGINT, _Exit); signal(SIGINT, other_call); - // CHECK-NOTES: :[[@LINE-1]]:18: warning: 'other_call' may not be asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:18: warning: standard function 'other_call' may not be asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler] signal(SIGINT, f_extern); - // CHECK-NOTES: :[[@LINE-1]]:18: warning: 'f_extern' may not be asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler] + // CHECK-NOTES: :[[@LINE-1]]:18: warning: cannot verify that external function 'f_extern' is asynchronous-safe; using it as a signal handler may be dangerous [bugprone-signal-handler] signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_DFL);