Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -41,6 +41,7 @@ #include "RedundantBranchConditionCheck.h" #include "ReservedIdentifierCheck.h" #include "SignalHandlerCheck.h" +#include "SignalInMultithreadedProgramCheck.h" #include "SignedCharMisuseCheck.h" #include "SizeofContainerCheck.h" #include "SizeofExpressionCheck.h" @@ -135,6 +136,8 @@ CheckFactories.registerCheck( "bugprone-reserved-identifier"); CheckFactories.registerCheck("bugprone-signal-handler"); + CheckFactories.registerCheck( + "bugprone-signal-in-multithreaded-program"); CheckFactories.registerCheck( "bugprone-signed-char-misuse"); CheckFactories.registerCheck( Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -36,6 +36,7 @@ RedundantBranchConditionCheck.cpp ReservedIdentifierCheck.cpp SignalHandlerCheck.cpp + SignalInMultithreadedProgramCheck.cpp SignedCharMisuseCheck.cpp SizeofContainerCheck.cpp SizeofExpressionCheck.cpp Index: clang-tools-extra/clang-tidy/bugprone/SignalInMultithreadedProgramCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SignalInMultithreadedProgramCheck.h @@ -0,0 +1,51 @@ +//===--- SignalInMultithreadedProgramCheck.h - clang-tidy -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIGNALINMULTITHREADEDPROGRAMCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIGNALINMULTITHREADEDPROGRAMCHECK_H + +#include "../ClangTidyCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include +#include + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Finds ``signal`` function calls when the program is multithreaded. The +/// check considers the analyzed program multithreaded if it finds at least +/// one threading-related function. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-signal-in-multithreaded-program.html +class SignalInMultithreadedProgramCheck : public ClangTidyCheck { +public: + SignalInMultithreadedProgramCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + ThreadList(Options.get( + "ThreadList", + "thrd_create;::std::thread;::boost::thread;pthread_t;CreateThread;" + "CreateRemoteThread;_beginthread;_beginthreadex")) {} + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + bool IsCPosix = false; + +private: + const std::string ThreadList; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIGNALINMULTITHREADEDPROGRAMCHECK_H Index: clang-tools-extra/clang-tidy/bugprone/SignalInMultithreadedProgramCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SignalInMultithreadedProgramCheck.cpp @@ -0,0 +1,94 @@ +//===--- SignalInMultithreadedProgramCheck.cpp - clang-tidy ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SignalInMultithreadedProgramCheck.h" +#include "../utils/Matchers.h" +#include "../utils/OptionsUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang::ast_matchers; +using namespace clang::ast_matchers::internal; + +namespace clang { +namespace tidy { +namespace bugprone { + +namespace { +class SignalInMultithreadedPPCallbacks : public PPCallbacks { +public: + explicit SignalInMultithreadedPPCallbacks( + SignalInMultithreadedProgramCheck &Check, const SourceManager &SM, + Preprocessor *PP) + : Check(Check), PP(PP) {} + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + const llvm::StringRef MacroName = MacroNameTok.getIdentifierInfo()->getName(); + if (MacroName == "_POSIX_C_SOURCE" || MacroName == "__unix__") { + Check.IsCPosix = true; + } + } + +private: + SignalInMultithreadedProgramCheck &Check; + Preprocessor *PP; +}; +} // namespace + +Matcher hasAnyListedName(const std::string &FunctionNames) { + const std::vector NameList = + utils::options::parseStringList(FunctionNames); + return hasAnyName(std::vector(NameList.begin(), NameList.end())); +} + +void SignalInMultithreadedProgramCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "ThreadList", ThreadList); +} + +void SignalInMultithreadedProgramCheck::registerMatchers(MatchFinder *Finder) { + + auto threadCall = anyOf( + hasDescendant(callExpr(ignoringImpCasts(hasDescendant(declRefExpr( + hasDeclaration(functionDecl(hasAnyListedName(ThreadList)))))))), + hasDescendant(varDecl(hasType(recordDecl(hasName("::std::thread"))))) + + ); + Finder->addMatcher( + callExpr( + ignoringImpCasts(hasDescendant(declRefExpr(hasDeclaration( + functionDecl(allOf(hasName("::signal"), parameterCountIs(2), + hasParameter(0, hasType(isInteger())))))))), + hasAncestor(compoundStmt(threadCall))) + .bind("signal"), + this); +} + +void SignalInMultithreadedProgramCheck::check( + const MatchFinder::MatchResult &Result) { + bool IsPosix = + IsCPosix || Result.Context->getTargetInfo().getTriple().getVendor() == + llvm::Triple::Apple; + if (IsPosix) + return; + const auto *MatchedSignal = Result.Nodes.getNodeAs("signal"); + diag(MatchedSignal->getExprLoc(), + "signal function should not be called in a multithreaded program"); +} + +void SignalInMultithreadedProgramCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + PP->addPPCallbacks( + ::std::make_unique(*this, SM, PP)); +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp +++ clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp @@ -12,6 +12,7 @@ #include "../bugprone/BadSignalToKillThreadCheck.h" #include "../bugprone/ReservedIdentifierCheck.h" #include "../bugprone/SignalHandlerCheck.h" +#include "../bugprone/SignalInMultithreadedProgramCheck.h" #include "../bugprone/SignedCharMisuseCheck.h" #include "../bugprone/SpuriouslyWakeUpFunctionsCheck.h" #include "../bugprone/UnhandledSelfAssignmentCheck.h" @@ -44,7 +45,7 @@ class CERTModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { - // C++ checkers + // C++ checks // CON CheckFactories.registerCheck( "cert-con54-cpp"); @@ -85,10 +86,12 @@ CheckFactories.registerCheck( "cert-oop58-cpp"); - // C checkers + // C checks // CON CheckFactories.registerCheck( "cert-con36-c"); + CheckFactories.registerCheck( + "cert-con37-c"); // DCL CheckFactories.registerCheck("cert-dcl03-c"); CheckFactories.registerCheck( Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -118,6 +118,16 @@ Finds functions registered as signal handlers that call non asynchronous-safe functions. +- New :doc:`bugprone-signal-in-multithreaded-program + ` check. + + Finds ``signal`` function calls when the program is multithreaded. The + check considers the analyzed program multithreaded if it finds at least + one threading-related function. + +- New :doc:`bugprone-suspicious-include + ` check. + - New :doc:`cert-sig30-c ` check. @@ -129,6 +139,16 @@ Flags functions with Cognitive Complexity metric exceeding the configured limit. +- New alias :doc:`cert-con37-c + ` to + :doc:`bugprone-signal-in-multithreaded-program + ` was added. + +- New alias :doc:`cert-con54-cpp + ` to + :doc:`bugprone-spuriously-wake-up-functions + ` was added. + Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^ Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-signal-in-multithreaded-program.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/bugprone-signal-in-multithreaded-program.rst @@ -0,0 +1,25 @@ +.. title:: clang-tidy - bugprone-signal-in-multithreaded-program + +bugprone-signal-in-multithreaded-program +======================================== + +Finds ``signal`` function calls when the program is multithreaded. The +check considers the analyzed program multithreaded if it finds at least +one threading-related function. + +.. code-block:: c + + signal(SIGUSR1, handler); + thrd_t tid; + +This check corresponds to the CERT C++ Coding Standard rule +`CON37-C. Do not call signal() in a multithreaded program +`_. + +Options +------- + +.. option:: ThreadList + + Semicolon-separated list of fully qualified names of thread call functions. + Defaults to ``thrd_create;::thread;boost::thread;pthread_t``. Index: clang-tools-extra/docs/clang-tidy/checks/cert-con37-c.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/cert-con37-c.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - cert-con37-c +.. meta:: + :http-equiv=refresh: 5;URL=bugprone-signal-in-multithreaded-program.html + +cert-con37-c +============ + +The cert-con37-c check is an alias, please see +`bugprone-signal-in-multithreaded-program `_ +for more information. Index: clang-tools-extra/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -79,6 +79,7 @@ `bugprone-redundant-branch-condition `_, "Yes" `bugprone-reserved-identifier `_, "Yes" `bugprone-signal-handler `_, + `bugprone-signal-in-multithreaded-program `_, `bugprone-signed-char-misuse `_, `bugprone-sizeof-container `_, `bugprone-sizeof-expression `_, @@ -316,6 +317,7 @@ :header: "Name", "Redirect", "Offers fixes" `cert-con36-c `_, `bugprone-spuriously-wake-up-functions `_, + `cert-con37-c `_, `bugprone-signal-in-multithreaded-program `_, `cert-con54-cpp `_, `bugprone-spuriously-wake-up-functions `_, `cert-dcl03-c `_, `misc-static-assert `_, "Yes" `cert-dcl16-c `_, `readability-uppercase-literal-suffix `_, "Yes" Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-in-multithreaded-program-config-std_thread.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-in-multithreaded-program-config-std_thread.cpp @@ -0,0 +1,37 @@ +// RUN: %check_clang_tidy %s bugprone-signal-in-multithreaded-program %t \ +// RUN: -config='{CheckOptions: \ +// RUN: [{key: bugprone-signal-in-multithreaded-program.ThreadList, value: "::thread"}]}' + +typedef int sig_atomic_t; +#define SIGUSR1 30 +#define NULL 0 + +void (*signal(int sig, void (*handler)(int)))(int); + +volatile sig_atomic_t flag = 0; + +void handler(int signum) { + flag = 1; +} + +void threadFunction() {} + +namespace std { +class thread { +public: + thread() noexcept; + template + explicit thread(Function &&f, Args &&... args); + thread(const thread &) = delete; + thread(thread &&) noexcept; +}; +} // namespace std + +int main() { + signal(SIGUSR1, handler); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: signal function should not be called in a multithreaded program [bugprone-signal-in-multithreaded-program] + + std::thread threadObj(threadFunction); + + return 0; +} Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-in-multithreaded-program-config-thrd_create.c =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-in-multithreaded-program-config-thrd_create.c @@ -0,0 +1,38 @@ +// RUN: %check_clang_tidy %s bugprone-signal-in-multithreaded-program %t \ +// RUN: -config='{CheckOptions: \ +// RUN: [{key: bugprone-signal-in-multithreaded-program.ThreadList, value: "thrd_create"}]}' + +typedef unsigned long int thrd_t; +typedef int (*thrd_start_t)(void *); +typedef int sig_atomic_t; +#define SIGUSR1 30 +#define NULL 0 + +void (*signal(int sig, void (*handler)(int)))(int); + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { return 0; }; +enum { + thrd_success = 0, +}; + +volatile sig_atomic_t flag = 0; + +void handler(int signum) { + flag = 1; +} + +int func(void *data) { + while (!flag) { + } + return 0; +} + +int main(void) { + signal(SIGUSR1, handler); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: signal function should not be called in a multithreaded program [bugprone-signal-in-multithreaded-program] + thrd_t tid; + + if (thrd_success != thrd_create(&tid, func, NULL)) { + } + return 0; +} Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-in-multithreaded-program-noconfig-std_thread.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-in-multithreaded-program-noconfig-std_thread.cpp @@ -0,0 +1,35 @@ +// RUN: %check_clang_tidy %s bugprone-signal-in-multithreaded-program %t + +typedef int sig_atomic_t; +#define SIGUSR1 30 +#define NULL 0 + +void (*signal(int sig, void (*handler)(int)))(int); + +volatile sig_atomic_t flag = 0; + +void handler(int signum) { + flag = 1; +} + +void threadFunction() {} + +namespace std { +class thread { +public: + thread() noexcept; + template + explicit thread(Function &&f, Args &&... args); + thread(const thread &) = delete; + thread(thread &&) noexcept; +}; +} // namespace std + +int main() { + signal(SIGUSR1, handler); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: signal function should not be called in a multithreaded program [bugprone-signal-in-multithreaded-program] + + std::thread threadObj(threadFunction); + + return 0; +} Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-in-multithreaded-program-noconfig-thrd_create.c =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-signal-in-multithreaded-program-noconfig-thrd_create.c @@ -0,0 +1,36 @@ +// RUN: %check_clang_tidy %s bugprone-signal-in-multithreaded-program %t + +typedef unsigned long int thrd_t; +typedef int (*thrd_start_t)(void *); +typedef int sig_atomic_t; +#define SIGUSR1 30 +#define NULL 0 + +void (*signal(int sig, void (*handler)(int)))(int); + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { return 0; }; +enum { + thrd_success = 0, +}; + +volatile sig_atomic_t flag = 0; + +void handler(int signum) { + flag = 1; +} + +int func(void *data) { + while (!flag) { + } + return 0; +} + +int main(void) { + signal(SIGUSR1, handler); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: signal function should not be called in a multithreaded program [bugprone-signal-in-multithreaded-program] + thrd_t tid; + + if (thrd_success != thrd_create(&tid, func, NULL)) { + } + return 0; +}