forked from OSchip/llvm-project
317 lines
6.9 KiB
C++
317 lines
6.9 KiB
C++
//===--- 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;
|
|
|
|
// Initial list was extracted from gcc documentation
|
|
static const clang::StringRef GlibcFunctions[] = {
|
|
"::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",
|
|
};
|
|
|
|
static const clang::StringRef PosixFunctions[] = {
|
|
"::asctime",
|
|
"::basename",
|
|
"::catgets",
|
|
"::crypt",
|
|
"::ctime",
|
|
"::dbm_clearerr",
|
|
"::dbm_close",
|
|
"::dbm_delete",
|
|
"::dbm_error",
|
|
"::dbm_fetch",
|
|
"::dbm_firstkey",
|
|
"::dbm_nextkey",
|
|
"::dbm_open",
|
|
"::dbm_store",
|
|
"::dirname",
|
|
"::dlerror",
|
|
"::drand48",
|
|
"::encrypt",
|
|
"::endgrent",
|
|
"::endpwent",
|
|
"::endutxent",
|
|
"::ftw",
|
|
"::getc_unlocked",
|
|
"::getchar_unlocked",
|
|
"::getdate",
|
|
"::getenv",
|
|
"::getgrent",
|
|
"::getgrgid",
|
|
"::getgrnam",
|
|
"::gethostent",
|
|
"::getlogin",
|
|
"::getnetbyaddr",
|
|
"::getnetbyname",
|
|
"::getnetent",
|
|
"::getopt",
|
|
"::getprotobyname",
|
|
"::getprotobynumber",
|
|
"::getprotoent",
|
|
"::getpwent",
|
|
"::getpwnam",
|
|
"::getpwuid",
|
|
"::getservbyname",
|
|
"::getservbyport",
|
|
"::getservent",
|
|
"::getutxent",
|
|
"::getutxid",
|
|
"::getutxline",
|
|
"::gmtime",
|
|
"::hcreate",
|
|
"::hdestroy",
|
|
"::hsearch",
|
|
"::inet_ntoa",
|
|
"::l64a",
|
|
"::lgamma",
|
|
"::lgammaf",
|
|
"::lgammal",
|
|
"::localeconv",
|
|
"::localtime",
|
|
"::lrand48",
|
|
"::mrand48",
|
|
"::nftw",
|
|
"::nl_langinfo",
|
|
"::ptsname",
|
|
"::putc_unlocked",
|
|
"::putchar_unlocked",
|
|
"::putenv",
|
|
"::pututxline",
|
|
"::rand",
|
|
"::readdir",
|
|
"::setenv",
|
|
"::setgrent",
|
|
"::setkey",
|
|
"::setpwent",
|
|
"::setutxent",
|
|
"::strerror",
|
|
"::strsignal",
|
|
"::strtok",
|
|
"::system",
|
|
"::ttyname",
|
|
"::unsetenv",
|
|
"::wcstombs",
|
|
"::wctomb",
|
|
};
|
|
|
|
namespace clang {
|
|
namespace tidy {
|
|
|
|
template <> struct OptionEnumMapping<concurrency::MtUnsafeCheck::FunctionSet> {
|
|
static llvm::ArrayRef<
|
|
std::pair<concurrency::MtUnsafeCheck::FunctionSet, StringRef>>
|
|
getEnumMapping() {
|
|
static constexpr std::pair<concurrency::MtUnsafeCheck::FunctionSet,
|
|
StringRef>
|
|
Mapping[] = {{concurrency::MtUnsafeCheck::FunctionSet::Posix, "posix"},
|
|
{concurrency::MtUnsafeCheck::FunctionSet::Glibc, "glibc"},
|
|
{concurrency::MtUnsafeCheck::FunctionSet::Any, "any"}};
|
|
return makeArrayRef(Mapping);
|
|
}
|
|
};
|
|
|
|
namespace concurrency {
|
|
|
|
static ast_matchers::internal::Matcher<clang::NamedDecl>
|
|
hasAnyMtUnsafeNames(MtUnsafeCheck::FunctionSet Libc) {
|
|
switch (Libc) {
|
|
case MtUnsafeCheck::FunctionSet::Posix:
|
|
return hasAnyName(PosixFunctions);
|
|
case MtUnsafeCheck::FunctionSet::Glibc:
|
|
return hasAnyName(GlibcFunctions);
|
|
case MtUnsafeCheck::FunctionSet::Any:
|
|
return anyOf(hasAnyName(PosixFunctions), hasAnyName(GlibcFunctions));
|
|
}
|
|
llvm_unreachable("invalid FunctionSet");
|
|
}
|
|
|
|
MtUnsafeCheck::MtUnsafeCheck(StringRef Name, ClangTidyContext *Context)
|
|
: ClangTidyCheck(Name, Context),
|
|
FuncSet(Options.get("FunctionSet", MtUnsafeCheck::FunctionSet::Any)) {}
|
|
|
|
void MtUnsafeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
|
Options.store(Opts, "FunctionSet", FuncSet);
|
|
}
|
|
|
|
void MtUnsafeCheck::registerMatchers(MatchFinder *Finder) {
|
|
Finder->addMatcher(
|
|
callExpr(callee(functionDecl(hasAnyMtUnsafeNames(FuncSet))))
|
|
.bind("mt-unsafe"),
|
|
this);
|
|
}
|
|
|
|
void MtUnsafeCheck::check(const MatchFinder::MatchResult &Result) {
|
|
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("mt-unsafe");
|
|
assert(Call && "Unhandled binding in the Matcher");
|
|
|
|
diag(Call->getBeginLoc(), "function is not thread safe");
|
|
}
|
|
|
|
} // namespace concurrency
|
|
} // namespace tidy
|
|
} // namespace clang
|