1 //===--- SignalHandlerCheck.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 "SignalHandlerCheck.h"
10 #include "clang/ASTMatchers/ASTMatchFinder.h"
11 #include "llvm/ADT/DepthFirstIterator.h"
12 #include "llvm/ADT/STLExtras.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 
19 template <>
20 struct OptionEnumMapping<
21     bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType> {
22   static llvm::ArrayRef<std::pair<
23       bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType, StringRef>>
24   getEnumMapping() {
25     static constexpr std::pair<
26         bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType, StringRef>
27         Mapping[] = {
28             {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType::Minimal,
29              "minimal"},
30             {bugprone::SignalHandlerCheck::AsyncSafeFunctionSetType::POSIX,
31              "POSIX"},
32         };
33     return makeArrayRef(Mapping);
34   }
35 };
36 
37 namespace bugprone {
38 
39 namespace {
40 
41 bool isSystemCall(const FunctionDecl *FD) {
42   // Find a possible redeclaration in system header.
43   // FIXME: Looking at the canonical declaration is not the most exact way
44   // to do this.
45 
46   // Most common case will be inclusion directly from a header.
47   // This works fine by using canonical declaration.
48   // a.c
49   // #include <sysheader.h>
50 
51   // Next most common case will be extern declaration.
52   // Can't catch this with either approach.
53   // b.c
54   // extern void sysfunc(void);
55 
56   // Canonical declaration is the first found declaration, so this works.
57   // c.c
58   // #include <sysheader.h>
59   // extern void sysfunc(void); // redecl won't matter
60 
61   // This does not work with canonical declaration.
62   // Probably this is not a frequently used case but may happen (the first
63   // declaration can be in a non-system header for example).
64   // d.c
65   // extern void sysfunc(void); // Canonical declaration, not in system header.
66   // #include <sysheader.h>
67 
68   return FD->getASTContext().getSourceManager().isInSystemHeader(
69       FD->getCanonicalDecl()->getLocation());
70 }
71 
72 /// Given a call graph node of a function and another one that is called from
73 /// this function, get a CallExpr of the corresponding function call.
74 /// It is unspecified which call is found if multiple calls exist, but the order
75 /// should be deterministic (depend only on the AST).
76 Expr *findCallExpr(const CallGraphNode *Caller, const CallGraphNode *Callee) {
77   auto FoundCallee = llvm::find_if(
78       Caller->callees(), [Callee](const CallGraphNode::CallRecord &Call) {
79         return Call.Callee == Callee;
80       });
81   assert(FoundCallee != Caller->end() &&
82          "Callee should be called from the caller function here.");
83   return FoundCallee->CallExpr;
84 }
85 
86 } // namespace
87 
88 AST_MATCHER(FunctionDecl, isSystemCall) { return isSystemCall(&Node); }
89 
90 SignalHandlerCheck::SignalHandlerCheck(StringRef Name,
91                                        ClangTidyContext *Context)
92     : ClangTidyCheck(Name, Context),
93       AsyncSafeFunctionSet(
94           Options.get("AsyncSafeFunctionSet", AsyncSafeFunctionSetType::POSIX)),
95       ConformingFunctions(AsyncSafeFunctionSet ==
96                                   AsyncSafeFunctionSetType::Minimal
97                               ? MinimalConformingFunctions
98                               : POSIXConformingFunctions) {}
99 
100 void SignalHandlerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
101   Options.store(Opts, "AsyncSafeFunctionSet", AsyncSafeFunctionSet);
102 }
103 
104 bool SignalHandlerCheck::isLanguageVersionSupported(
105     const LangOptions &LangOpts) const {
106   // FIXME: Make the checker useful on C++ code.
107   if (LangOpts.CPlusPlus)
108     return false;
109 
110   return true;
111 }
112 
113 void SignalHandlerCheck::registerMatchers(MatchFinder *Finder) {
114   auto SignalFunction = functionDecl(hasAnyName("::signal", "::std::signal"),
115                                      parameterCountIs(2), isSystemCall());
116   auto HandlerExpr =
117       declRefExpr(hasDeclaration(functionDecl().bind("handler_decl")),
118                   unless(isExpandedFromMacro("SIG_IGN")),
119                   unless(isExpandedFromMacro("SIG_DFL")))
120           .bind("handler_expr");
121   Finder->addMatcher(
122       callExpr(callee(SignalFunction), hasArgument(1, HandlerExpr))
123           .bind("register_call"),
124       this);
125 }
126 
127 void SignalHandlerCheck::check(const MatchFinder::MatchResult &Result) {
128   const auto *SignalCall = Result.Nodes.getNodeAs<CallExpr>("register_call");
129   const auto *HandlerDecl =
130       Result.Nodes.getNodeAs<FunctionDecl>("handler_decl");
131   const auto *HandlerExpr = Result.Nodes.getNodeAs<DeclRefExpr>("handler_expr");
132   assert(SignalCall && HandlerDecl && HandlerExpr &&
133          "All of these should exist in a match here.");
134 
135   if (CG.size() <= 1) {
136     // Call graph must be populated with the entire TU at the beginning.
137     // (It is possible to add a single function but the functions called from it
138     // are not analysed in this case.)
139     CG.addToCallGraph(const_cast<TranslationUnitDecl *>(
140         HandlerDecl->getTranslationUnitDecl()));
141     assert(CG.size() > 1 &&
142            "There should be at least one function added to call graph.");
143   }
144 
145   // Check for special case when the signal handler itself is an unsafe external
146   // function.
147   if (!isFunctionAsyncSafe(HandlerDecl)) {
148     reportBug(HandlerDecl, HandlerExpr, /*DirectHandler=*/true);
149     return;
150   }
151 
152   CallGraphNode *HandlerNode = CG.getNode(HandlerDecl);
153   // Signal handler can be external but not unsafe, no call graph in this case.
154   if (!HandlerNode)
155     return;
156   // Start from signal handler and visit every function call.
157   for (auto Itr = llvm::df_begin(HandlerNode), ItrE = llvm::df_end(HandlerNode);
158        Itr != ItrE; ++Itr) {
159     const auto *CallF = dyn_cast<FunctionDecl>((*Itr)->getDecl());
160     if (CallF && !isFunctionAsyncSafe(CallF)) {
161       assert(Itr.getPathLength() >= 2);
162       reportBug(CallF, findCallExpr(Itr.getPath(Itr.getPathLength() - 2), *Itr),
163                 /*DirectHandler=*/false);
164       reportHandlerCommon(Itr, SignalCall, HandlerDecl, HandlerExpr);
165     }
166   }
167 }
168 
169 bool SignalHandlerCheck::isFunctionAsyncSafe(const FunctionDecl *FD) const {
170   if (isSystemCall(FD))
171     return isSystemCallAsyncSafe(FD);
172   // For external (not checkable) functions assume that these are unsafe.
173   return FD->hasBody();
174 }
175 
176 bool SignalHandlerCheck::isSystemCallAsyncSafe(const FunctionDecl *FD) const {
177   const IdentifierInfo *II = FD->getIdentifier();
178   // Unnamed functions are not explicitly allowed.
179   if (!II)
180     return false;
181 
182   // FIXME: Improve for C++ (check for namespace).
183   if (ConformingFunctions.count(II->getName()))
184     return true;
185 
186   return false;
187 }
188 
189 void SignalHandlerCheck::reportBug(const FunctionDecl *CalledFunction,
190                                    const Expr *CallOrRef, bool DirectHandler) {
191   diag(CallOrRef->getBeginLoc(),
192        "%0 may not be asynchronous-safe; %select{calling it from|using it as}1 "
193        "a signal handler may be dangerous")
194       << CalledFunction << DirectHandler;
195 }
196 
197 void SignalHandlerCheck::reportHandlerCommon(
198     llvm::df_iterator<clang::CallGraphNode *> Itr, const CallExpr *SignalCall,
199     const FunctionDecl *HandlerDecl, const Expr *HandlerRef) {
200   int CallLevel = Itr.getPathLength() - 2;
201   assert(CallLevel >= -1 && "Empty iterator?");
202 
203   const CallGraphNode *Caller = Itr.getPath(CallLevel + 1), *Callee = nullptr;
204   while (CallLevel >= 0) {
205     Callee = Caller;
206     Caller = Itr.getPath(CallLevel);
207     const Expr *CE = findCallExpr(Caller, Callee);
208     diag(CE->getBeginLoc(), "function %0 called here from %1",
209          DiagnosticIDs::Note)
210         << cast<FunctionDecl>(Callee->getDecl())
211         << cast<FunctionDecl>(Caller->getDecl());
212     --CallLevel;
213   }
214 
215   diag(HandlerRef->getBeginLoc(),
216        "function %0 registered here as signal handler", DiagnosticIDs::Note)
217       << HandlerDecl;
218 }
219 
220 // This is the minimal set of safe functions.
221 // https://wiki.sei.cmu.edu/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers
222 llvm::StringSet<> SignalHandlerCheck::MinimalConformingFunctions{
223     "signal", "abort", "_Exit", "quick_exit"};
224 
225 // The POSIX-defined set of safe functions.
226 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
227 // 'quick_exit' is added to the set additionally because it looks like the
228 // mentioned POSIX specification was not updated after 'quick_exit' appeared
229 // in the C11 standard.
230 // Also, we want to keep the "minimal set" a subset of the "POSIX set".
231 llvm::StringSet<> SignalHandlerCheck::POSIXConformingFunctions{
232     "_Exit",
233     "_exit",
234     "abort",
235     "accept",
236     "access",
237     "aio_error",
238     "aio_return",
239     "aio_suspend",
240     "alarm",
241     "bind",
242     "cfgetispeed",
243     "cfgetospeed",
244     "cfsetispeed",
245     "cfsetospeed",
246     "chdir",
247     "chmod",
248     "chown",
249     "clock_gettime",
250     "close",
251     "connect",
252     "creat",
253     "dup",
254     "dup2",
255     "execl",
256     "execle",
257     "execv",
258     "execve",
259     "faccessat",
260     "fchdir",
261     "fchmod",
262     "fchmodat",
263     "fchown",
264     "fchownat",
265     "fcntl",
266     "fdatasync",
267     "fexecve",
268     "ffs",
269     "fork",
270     "fstat",
271     "fstatat",
272     "fsync",
273     "ftruncate",
274     "futimens",
275     "getegid",
276     "geteuid",
277     "getgid",
278     "getgroups",
279     "getpeername",
280     "getpgrp",
281     "getpid",
282     "getppid",
283     "getsockname",
284     "getsockopt",
285     "getuid",
286     "htonl",
287     "htons",
288     "kill",
289     "link",
290     "linkat",
291     "listen",
292     "longjmp",
293     "lseek",
294     "lstat",
295     "memccpy",
296     "memchr",
297     "memcmp",
298     "memcpy",
299     "memmove",
300     "memset",
301     "mkdir",
302     "mkdirat",
303     "mkfifo",
304     "mkfifoat",
305     "mknod",
306     "mknodat",
307     "ntohl",
308     "ntohs",
309     "open",
310     "openat",
311     "pause",
312     "pipe",
313     "poll",
314     "posix_trace_event",
315     "pselect",
316     "pthread_kill",
317     "pthread_self",
318     "pthread_sigmask",
319     "quick_exit",
320     "raise",
321     "read",
322     "readlink",
323     "readlinkat",
324     "recv",
325     "recvfrom",
326     "recvmsg",
327     "rename",
328     "renameat",
329     "rmdir",
330     "select",
331     "sem_post",
332     "send",
333     "sendmsg",
334     "sendto",
335     "setgid",
336     "setpgid",
337     "setsid",
338     "setsockopt",
339     "setuid",
340     "shutdown",
341     "sigaction",
342     "sigaddset",
343     "sigdelset",
344     "sigemptyset",
345     "sigfillset",
346     "sigismember",
347     "siglongjmp",
348     "signal",
349     "sigpause",
350     "sigpending",
351     "sigprocmask",
352     "sigqueue",
353     "sigset",
354     "sigsuspend",
355     "sleep",
356     "sockatmark",
357     "socket",
358     "socketpair",
359     "stat",
360     "stpcpy",
361     "stpncpy",
362     "strcat",
363     "strchr",
364     "strcmp",
365     "strcpy",
366     "strcspn",
367     "strlen",
368     "strncat",
369     "strncmp",
370     "strncpy",
371     "strnlen",
372     "strpbrk",
373     "strrchr",
374     "strspn",
375     "strstr",
376     "strtok_r",
377     "symlink",
378     "symlinkat",
379     "tcdrain",
380     "tcflow",
381     "tcflush",
382     "tcgetattr",
383     "tcgetpgrp",
384     "tcsendbreak",
385     "tcsetattr",
386     "tcsetpgrp",
387     "time",
388     "timer_getoverrun",
389     "timer_gettime",
390     "timer_settime",
391     "times",
392     "umask",
393     "uname",
394     "unlink",
395     "unlinkat",
396     "utime",
397     "utimensat",
398     "utimes",
399     "wait",
400     "waitpid",
401     "wcpcpy",
402     "wcpncpy",
403     "wcscat",
404     "wcschr",
405     "wcscmp",
406     "wcscpy",
407     "wcscspn",
408     "wcslen",
409     "wcsncat",
410     "wcsncmp",
411     "wcsncpy",
412     "wcsnlen",
413     "wcspbrk",
414     "wcsrchr",
415     "wcsspn",
416     "wcsstr",
417     "wcstok",
418     "wmemchr",
419     "wmemcmp",
420     "wmemcpy",
421     "wmemmove",
422     "wmemset",
423     "write"};
424 
425 } // namespace bugprone
426 } // namespace tidy
427 } // namespace clang
428