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 @@ -7,6 +7,7 @@ DefinitionsInHeadersCheck.cpp MiscTidyModule.cpp MisplacedConstCheck.cpp + MtUnsafeCheck.cpp NewDeleteOverloadsCheck.cpp NoRecursionCheck.cpp NonCopyableObjects.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 @@ -11,6 +11,7 @@ #include "../ClangTidyModuleRegistry.h" #include "DefinitionsInHeadersCheck.h" #include "MisplacedConstCheck.h" +#include "MtUnsafeCheck.h" #include "NewDeleteOverloadsCheck.h" #include "NoRecursionCheck.h" #include "NonCopyableObjects.h" @@ -34,6 +35,8 @@ CheckFactories.registerCheck( "misc-definitions-in-headers"); CheckFactories.registerCheck("misc-misplaced-const"); + CheckFactories.registerCheck( + "misc-mt-unsafe"); CheckFactories.registerCheck( "misc-new-delete-overloads"); CheckFactories.registerCheck("misc-no-recursion"); Index: clang-tools-extra/clang-tidy/misc/MtUnsafeCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/misc/MtUnsafeCheck.h @@ -0,0 +1,34 @@ +//===--- MtUnsafeCheck.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_MTUNSAFECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MTUNSAFECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Checks that non-thread-safe functions are not used. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-mt-unsafe.html +class MtUnsafeCheck : public ClangTidyCheck { +public: + MtUnsafeCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MTUNSAFECHECK_H Index: clang-tools-extra/clang-tidy/misc/MtUnsafeCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/misc/MtUnsafeCheck.cpp @@ -0,0 +1,204 @@ +//===--- MtUnsafeCheck.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 "MtUnsafeCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +namespace { + +// Initial list was extracted from gcc documentation +const StringRef functions[] = { + "::argp_error", + "::argp_help", + "::argp_parse", + "::argp_state_help", + "::argp_usage", + "::asctime", + "::clearenv", + "::crypt", + "::ctime", + "::cuserid", + "::drand48", + "::ecvt", + "::encrypt", + "::endfsent", + "::endgrent", + "::endhostent", + "::endnetent", + "::endnetgrent", + "::endprotoent", + "::endpwent", + "::endservent", + "::endutent", + "::endutxent", + "::erand48", + "::error_at_line", + "::exit", + "::fcloseall", + "::fcvt", + "::fgetgrent", + "::fgetpwent", + "::gammal", + "::getchar_unlocked", + "::getdate", + "::getfsent", + "::getfsfile", + "::getfsspec", + "::getgrent", + "::getgrent_r", + "::getgrgid", + "::getgrnam", + "::gethostbyaddr", + "::gethostbyname", + "::gethostbyname2", + "::gethostent", + "::getlogin", + "::getmntent", + "::getnetbyaddr", + "::getnetbyname", + "::getnetent", + "::getnetgrent", + "::getnetgrent_r", + "::getopt", + "::getopt_long", + "::getopt_long_only", + "::getpass", + "::getprotobyname", + "::getprotobynumber", + "::getprotoent", + "::getpwent", + "::getpwent_r", + "::getpwnam", + "::getpwuid", + "::getservbyname", + "::getservbyport", + "::getservent", + "::getutent", + "::getutent_r", + "::getutid", + "::getutid_r", + "::getutline", + "::getutline_r", + "::getutxent", + "::getutxid", + "::getutxline", + "::getwchar_unlocked", + "::glob", + "::glob64", + "::gmtime", + "::hcreate", + "::hdestroy", + "::hsearch", + "::innetgr", + "::jrand48", + "::l64a", + "::lcong48", + "::lgammafNx", + "::localeconv", + "::localtime", + "::login", + "::login_tty", + "::logout", + "::logwtmp", + "::lrand48", + "::mallinfo", + "::mallopt", + "::mblen", + "::mbrlen", + "::mbrtowc", + "::mbsnrtowcs", + "::mbsrtowcs", + "::mbtowc", + "::mcheck", + "::mprobe", + "::mrand48", + "::mtrace", + "::muntrace", + "::nrand48", + "::__ppc_get_timebase_freq", + "::ptsname", + "::putchar_unlocked", + "::putenv", + "::pututline", + "::pututxline", + "::putwchar_unlocked", + "::qecvt", + "::qfcvt", + "::register_printf_function", + "::seed48", + "::setenv", + "::setfsent", + "::setgrent", + "::sethostent", + "::sethostid", + "::setkey", + "::setlocale", + "::setlogmask", + "::setnetent", + "::setnetgrent", + "::setprotoent", + "::setpwent", + "::setservent", + "::setutent", + "::setutxent", + "::siginterrupt", + "::sigpause", + "::sigprocmask", + "::sigsuspend", + "::sleep", + "::srand48", + "::strerror", + "::strsignal", + "::strtok", + "::tcflow", + "::tcsendbreak", + "::tmpnam", + "::ttyname", + "::unsetenv", + "::updwtmp", + "::utmpname", + "::utmpxname", + "::valloc", + "::vlimit", + "::wcrtomb", + "::wcsnrtombs", + "::wcsrtombs", + "::wctomb", + "::wordexp", +}; + +ast_matchers::internal::Matcher hasAnyMtUnsafeNames() { + return hasAnyName(functions); +} + +} // namespace + +void MtUnsafeCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr(callee(functionDecl(hasAnyMtUnsafeNames()))).bind("mt-unsafe"), + this); +} + +void MtUnsafeCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Call = Result.Nodes.getNodeAs("mt-unsafe"); + assert(Call && "Unhandled binding in the Matcher"); + + diag(Call->getBeginLoc(), "function is not thread safe") + << SourceRange(Call->getBeginLoc(), Call->getEndLoc()); +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -106,6 +106,10 @@ Finds condition variables in nested ``if`` statements that were also checked in the outer ``if`` statement and were not changed. +- New :doc:`misc-mt-unsafe ` check. + + Finds thread-unsafe functions usage. + - New :doc:`readability-function-cognitive-complexity ` 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 @@ -30,7 +30,7 @@ `abseil-time-comparison `_, "Yes" `abseil-time-subtraction `_, "Yes" `abseil-upgrade-duration-conversions `_, "Yes" - `altera-struct-pack-align `_, + `altera-struct-pack-align `_, "Yes" `android-cloexec-accept `_, "Yes" `android-cloexec-accept4 `_, `android-cloexec-creat `_, "Yes" @@ -143,6 +143,7 @@ `cppcoreguidelines-narrowing-conversions `_, `cppcoreguidelines-no-malloc `_, `cppcoreguidelines-owning-memory `_, + `cppcoreguidelines-prefer-member-initializer `_, "Yes" `cppcoreguidelines-pro-bounds-array-to-pointer-decay `_, `cppcoreguidelines-pro-bounds-constant-array-index `_, "Yes" `cppcoreguidelines-pro-bounds-pointer-arithmetic `_, @@ -179,7 +180,6 @@ `google-readability-todo `_, `google-runtime-int `_, `google-runtime-operator `_, - `google-runtime-references `_, `google-upgrade-googletest-case `_, "Yes" `hicpp-avoid-goto `_, `hicpp-exception-baseclass `_, @@ -198,6 +198,7 @@ `llvmlibc-restrict-system-libc-headers `_, "Yes" `misc-definitions-in-headers `_, "Yes" `misc-misplaced-const `_, + `misc-mt-unsafe `_, "Yes" `misc-new-delete-overloads `_, `misc-no-recursion `_, `misc-non-copyable-objects `_, Index: clang-tools-extra/docs/clang-tidy/checks/misc-mt-unsafe.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/misc-mt-unsafe.rst @@ -0,0 +1,16 @@ +.. title:: clang-tidy - misc-mt-unsafe + +misc-mt-unsafe +============== + +Checks for some thread-unsafe functions against a black list of +known-to-be-unsafe functions. Usually they access static variables without +synchronization (e.g. gmtime(3)) or utilize signals in a racy way. + +Examples: + +.. code-block:: c++ + + tm = gmtime(timep); // uses a global buffer + + sleep(1); // implementation may use SIGALRM Index: clang-tools-extra/test/clang-tidy/checkers/misc-mt-unsafe.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/misc-mt-unsafe.cpp @@ -0,0 +1,18 @@ +// RUN: %check_clang_tidy %s misc-mt-unsafe %t + +#include +#include + +void foo() { + sleep(2); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function is not thread safe [misc-mt-unsafe] + + ::sleep(2); + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: function is not thread safe [misc-mt-unsafe] + + time_t tt{}; + auto tm = gmtime(&tt); + // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: function is not thread safe [misc-mt-unsafe] + tm = ::gmtime(&tt); + // CHECK-MESSAGES: :[[@LINE-4]]:8: warning: function is not thread safe [misc-mt-unsafe] +}