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