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