MtUnsafeCheck.cpp 6.9 KB

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