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

source code of clang-tools-extra/clang-tidy/concurrency/MtUnsafeCheck.cpp