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/ASTMatchers/ASTMatchFinder.h"
11
12using namespace clang::ast_matchers;
13
14// Initial list was extracted from gcc documentation
15static 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(LocalName: "FunctionSet", Default: MtUnsafeCheck::FunctionSet::Any)) {}
292
293void MtUnsafeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
294 Options.store(Options&: Opts, LocalName: "FunctionSet", Value: FuncSet);
295}
296
297void MtUnsafeCheck::registerMatchers(MatchFinder *Finder) {
298 Finder->addMatcher(
299 NodeMatch: callExpr(callee(InnerMatcher: functionDecl(hasAnyMtUnsafeNames(Libc: FuncSet))))
300 .bind(ID: "mt-unsafe"),
301 Action: this);
302}
303
304void MtUnsafeCheck::check(const MatchFinder::MatchResult &Result) {
305 const auto *Call = Result.Nodes.getNodeAs<CallExpr>(ID: "mt-unsafe");
306 assert(Call && "Unhandled binding in the Matcher");
307
308 diag(Loc: Call->getBeginLoc(), Description: "function is not thread safe");
309}
310
311} // namespace concurrency
312} // namespace clang::tidy
313

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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