313 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MtUnsafeCheck.h"10#include "clang/ASTMatchers/ASTMatchFinder.h"11 12using namespace clang::ast_matchers;13 14// Initial list was extracted from gcc documentation15static const clang::StringRef GlibcFunctions[] = {16 "::argp_error",17 "::argp_help",18 "::argp_parse",19 "::argp_state_help",20 "::argp_usage",21 "::asctime",22 "::clearenv",23 "::crypt",24 "::ctime",25 "::cuserid",26 "::drand48",27 "::ecvt",28 "::encrypt",29 "::endfsent",30 "::endgrent",31 "::endhostent",32 "::endnetent",33 "::endnetgrent",34 "::endprotoent",35 "::endpwent",36 "::endservent",37 "::endutent",38 "::endutxent",39 "::erand48",40 "::error_at_line",41 "::exit",42 "::fcloseall",43 "::fcvt",44 "::fgetgrent",45 "::fgetpwent",46 "::gammal",47 "::getchar_unlocked",48 "::getdate",49 "::getfsent",50 "::getfsfile",51 "::getfsspec",52 "::getgrent",53 "::getgrent_r",54 "::getgrgid",55 "::getgrnam",56 "::gethostbyaddr",57 "::gethostbyname",58 "::gethostbyname2",59 "::gethostent",60 "::getlogin",61 "::getmntent",62 "::getnetbyaddr",63 "::getnetbyname",64 "::getnetent",65 "::getnetgrent",66 "::getnetgrent_r",67 "::getopt",68 "::getopt_long",69 "::getopt_long_only",70 "::getpass",71 "::getprotobyname",72 "::getprotobynumber",73 "::getprotoent",74 "::getpwent",75 "::getpwent_r",76 "::getpwnam",77 "::getpwuid",78 "::getservbyname",79 "::getservbyport",80 "::getservent",81 "::getutent",82 "::getutent_r",83 "::getutid",84 "::getutid_r",85 "::getutline",86 "::getutline_r",87 "::getutxent",88 "::getutxid",89 "::getutxline",90 "::getwchar_unlocked",91 "::glob",92 "::glob64",93 "::gmtime",94 "::hcreate",95 "::hdestroy",96 "::hsearch",97 "::innetgr",98 "::jrand48",99 "::l64a",100 "::lcong48",101 "::lgammafNx",102 "::localeconv",103 "::localtime",104 "::login",105 "::login_tty",106 "::logout",107 "::logwtmp",108 "::lrand48",109 "::mallinfo",110 "::mallopt",111 "::mblen",112 "::mbrlen",113 "::mbrtowc",114 "::mbsnrtowcs",115 "::mbsrtowcs",116 "::mbtowc",117 "::mcheck",118 "::mprobe",119 "::mrand48",120 "::mtrace",121 "::muntrace",122 "::nrand48",123 "::__ppc_get_timebase_freq",124 "::ptsname",125 "::putchar_unlocked",126 "::putenv",127 "::pututline",128 "::pututxline",129 "::putwchar_unlocked",130 "::qecvt",131 "::qfcvt",132 "::register_printf_function",133 "::seed48",134 "::setenv",135 "::setfsent",136 "::setgrent",137 "::sethostent",138 "::sethostid",139 "::setkey",140 "::setlocale",141 "::setlogmask",142 "::setnetent",143 "::setnetgrent",144 "::setprotoent",145 "::setpwent",146 "::setservent",147 "::setutent",148 "::setutxent",149 "::siginterrupt",150 "::sigpause",151 "::sigprocmask",152 "::sigsuspend",153 "::sleep",154 "::srand48",155 "::strsignal",156 "::strtok",157 "::tcflow",158 "::tcsendbreak",159 "::tmpnam",160 "::ttyname",161 "::unsetenv",162 "::updwtmp",163 "::utmpname",164 "::utmpxname",165 "::valloc",166 "::vlimit",167 "::wcrtomb",168 "::wcsnrtombs",169 "::wcsrtombs",170 "::wctomb",171 "::wordexp",172};173 174static const clang::StringRef PosixFunctions[] = {175 "::asctime",176 "::basename",177 "::catgets",178 "::crypt",179 "::ctime",180 "::dbm_clearerr",181 "::dbm_close",182 "::dbm_delete",183 "::dbm_error",184 "::dbm_fetch",185 "::dbm_firstkey",186 "::dbm_nextkey",187 "::dbm_open",188 "::dbm_store",189 "::dirname",190 "::dlerror",191 "::drand48",192 "::encrypt",193 "::endgrent",194 "::endpwent",195 "::endutxent",196 "::ftw",197 "::getc_unlocked",198 "::getchar_unlocked",199 "::getdate",200 "::getenv",201 "::getgrent",202 "::getgrgid",203 "::getgrnam",204 "::gethostent",205 "::getlogin",206 "::getnetbyaddr",207 "::getnetbyname",208 "::getnetent",209 "::getopt",210 "::getprotobyname",211 "::getprotobynumber",212 "::getprotoent",213 "::getpwent",214 "::getpwnam",215 "::getpwuid",216 "::getservbyname",217 "::getservbyport",218 "::getservent",219 "::getutxent",220 "::getutxid",221 "::getutxline",222 "::gmtime",223 "::hcreate",224 "::hdestroy",225 "::hsearch",226 "::inet_ntoa",227 "::l64a",228 "::lgamma",229 "::lgammaf",230 "::lgammal",231 "::localeconv",232 "::localtime",233 "::lrand48",234 "::mrand48",235 "::nftw",236 "::nl_langinfo",237 "::ptsname",238 "::putc_unlocked",239 "::putchar_unlocked",240 "::putenv",241 "::pututxline",242 "::rand",243 "::readdir",244 "::setenv",245 "::setgrent",246 "::setkey",247 "::setpwent",248 "::setutxent",249 "::strerror",250 "::strsignal",251 "::strtok",252 "::system",253 "::ttyname",254 "::unsetenv",255 "::wcstombs",256 "::wctomb",257};258 259namespace clang::tidy {260 261template <> struct OptionEnumMapping<concurrency::MtUnsafeCheck::FunctionSet> {262 static llvm::ArrayRef<263 std::pair<concurrency::MtUnsafeCheck::FunctionSet, StringRef>>264 getEnumMapping() {265 static constexpr std::pair<concurrency::MtUnsafeCheck::FunctionSet,266 StringRef>267 Mapping[] = {{concurrency::MtUnsafeCheck::FunctionSet::Posix, "posix"},268 {concurrency::MtUnsafeCheck::FunctionSet::Glibc, "glibc"},269 {concurrency::MtUnsafeCheck::FunctionSet::Any, "any"}};270 return {Mapping};271 }272};273 274namespace concurrency {275 276static ast_matchers::internal::Matcher<clang::NamedDecl>277hasAnyMtUnsafeNames(MtUnsafeCheck::FunctionSet Libc) {278 switch (Libc) {279 case MtUnsafeCheck::FunctionSet::Posix:280 return hasAnyName(PosixFunctions);281 case MtUnsafeCheck::FunctionSet::Glibc:282 return hasAnyName(GlibcFunctions);283 case MtUnsafeCheck::FunctionSet::Any:284 return anyOf(hasAnyName(PosixFunctions), hasAnyName(GlibcFunctions));285 }286 llvm_unreachable("invalid FunctionSet");287}288 289MtUnsafeCheck::MtUnsafeCheck(StringRef Name, ClangTidyContext *Context)290 : ClangTidyCheck(Name, Context),291 FuncSet(Options.get("FunctionSet", MtUnsafeCheck::FunctionSet::Any)) {}292 293void MtUnsafeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {294 Options.store(Opts, "FunctionSet", FuncSet);295}296 297void MtUnsafeCheck::registerMatchers(MatchFinder *Finder) {298 Finder->addMatcher(299 callExpr(callee(functionDecl(hasAnyMtUnsafeNames(FuncSet))))300 .bind("mt-unsafe"),301 this);302}303 304void MtUnsafeCheck::check(const MatchFinder::MatchResult &Result) {305 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("mt-unsafe");306 assert(Call && "Unhandled binding in the Matcher");307 308 diag(Call->getBeginLoc(), "function is not thread safe");309}310 311} // namespace concurrency312} // namespace clang::tidy313