Index: clang-tools-extra/clang-tidy/misc/BadSignalToKillThreadCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/misc/BadSignalToKillThreadCheck.h @@ -0,0 +1,39 @@ +//===--- BadSignalToKillThreadCheck.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_MISC_BADSIGNALTOKILLTHREADCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BADSIGNALTOKILLTHREADCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Do not send an uncaught signal to kill a thread because the signal kills the +/// entire process, not just the individual thread. To learn more about this +/// rule see: +/// https://wiki.sei.cmu.edu/confluence/display/c/POS44-C.+Do+not+use+signals+to+terminate+threads +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-bad-signal-to-kill-thread.html +class BadSignalToKillThreadCheck : public ClangTidyCheck { +public: + BadSignalToKillThreadCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + 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; + Optional SigtermValue; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BADSIGNALTOKILLTHREADCHECK_H Index: clang-tools-extra/clang-tidy/misc/BadSignalToKillThreadCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/misc/BadSignalToKillThreadCheck.cpp @@ -0,0 +1,63 @@ +//===--- BadSignalToKillThreadCheck.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 "BadSignalToKillThreadCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void BadSignalToKillThreadCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr(allOf(callee(functionDecl(hasName("::pthread_kill"))), + argumentCountIs(2)), + hasArgument(1, integerLiteral().bind("integer-literal"))) + .bind("thread-kill"), + this); +} + +static Preprocessor *PP; + +void BadSignalToKillThreadCheck::check(const MatchFinder::MatchResult &Result) { + Preprocessor::macro_iterator It = PP->macro_begin(); + while (It != PP->macro_end() && !SigtermValue.hasValue()) { + if (It->first->getName() == "SIGTERM") { + const MacroInfo *MI = PP->getMacroInfo(It->first); + const Token &T = MI->tokens().back(); + StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength()); + llvm::APInt IntValue; + ValueStr.getAsInteger(10, IntValue); + SigtermValue = IntValue.getZExtValue(); + } + + ++It; + } + if (!SigtermValue) + return; + + const auto *MatchedExpr = Result.Nodes.getNodeAs("thread-kill"); + const auto *MatchedIntLiteral = + Result.Nodes.getNodeAs("integer-literal"); + if (MatchedIntLiteral->getValue() == *SigtermValue) { + diag(MatchedExpr->getBeginLoc(), + "Thread should not be terminated by SIGTERM signal."); + } +} + +void BadSignalToKillThreadCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *pp, Preprocessor *ModuleExpanderPP) { + PP = pp; +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyMiscModule + BadSignalToKillThreadCheck.cpp DefinitionsInHeadersCheck.cpp MiscTidyModule.cpp MisplacedConstCheck.cpp Index: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "BadSignalToKillThreadCheck.h" #include "DefinitionsInHeadersCheck.h" #include "MisplacedConstCheck.h" #include "NewDeleteOverloadsCheck.h" @@ -30,6 +31,8 @@ class MiscModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "misc-bad-signal-to-kill-thread"); CheckFactories.registerCheck( "misc-definitions-in-headers"); CheckFactories.registerCheck("misc-misplaced-const"); Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -115,6 +115,14 @@ Finds historical use of ``unsigned`` to hold vregs and physregs and rewrites them to use ``Register`` +- New :doc:`misc-bad-signal-to-kill-thread + ` check. + + Finds function calls when an uncaught signal try to kill a thread and + the signal kills the entire process, not just the individual thread. + To learn more about this rule please visit the following page: + https://wiki.sei.cmu.edu/confluence/display/c/POS44-C.+Do+not+use+signals+to+terminate+threads + - New :doc:`objc-missing-hash ` check. 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 @@ -282,6 +282,7 @@ llvm-prefer-isa-or-dyn-cast-in-conditionals llvm-prefer-register-over-unsigned llvm-twine-local + misc-bad-signal-to-kill-thread misc-definitions-in-headers misc-misplaced-const misc-new-delete-overloads Index: clang-tools-extra/docs/clang-tidy/checks/misc-bad-signal-to-kill-thread.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/misc-bad-signal-to-kill-thread.rst @@ -0,0 +1,12 @@ +.. title:: clang-tidy - misc-bad-signal-to-kill-thread + +misc-bad-signal-to-kill-thread +============================== + +Warn on uses of the ``pthread_kill`` function when thread is +terminated by ``SIGTERM`` signal. Use any signal except +``SIGTERM`` or ``SIGKILL``. + +.. code-block: c++ + + pthread_kill(thread, SIGTERM); Index: clang-tools-extra/test/clang-tidy/misc-bad-signal-to-kill-thread.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/misc-bad-signal-to-kill-thread.cpp @@ -0,0 +1,39 @@ +// RUN: %check_clang_tidy %s misc-bad-signal-to-kill-thread %t + +#define SIGTERM 15 +#define SIGINT 2 +using pthread_t = int; +using pthread_attr_t = int; + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg); + +int pthread_kill(pthread_t thread, int sig); + +int pthread_cancel(pthread_t thread); + +void *test_func_return_a_pointer(void *foo); + +int main() { + int result; + pthread_t thread; + + if ((result = pthread_create(&thread, nullptr, test_func_return_a_pointer, 0)) != 0) { + } + if ((result = pthread_kill(thread, SIGTERM)) != 0) { + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Thread should not be terminated by SIGTERM signal. [misc-bad-signal-to-kill-thread] + } + + //compliant solution + if ((result = pthread_cancel(thread)) != 0) { + } + + if ((result = pthread_kill(thread, SIGINT)) != 0) { + } + if ((result = pthread_kill(thread, 0xF)) != 0) { + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Thread should not be terminated by SIGTERM signal. [misc-bad-signal-to-kill-thread] + } + + + return 0; +}