Clang Project

clang_source_code/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
1//= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-//
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// This defines UnixAPIChecker, which is an assortment of checks on calls
10// to various, widely used UNIX/Posix functions.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15#include "clang/Basic/TargetInfo.h"
16#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17#include "clang/StaticAnalyzer/Core/Checker.h"
18#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20#include "llvm/ADT/Optional.h"
21#include "llvm/ADT/STLExtras.h"
22#include "llvm/ADT/SmallString.h"
23#include "llvm/Support/raw_ostream.h"
24
25using namespace clang;
26using namespace ento;
27
28enum class OpenVariant {
29  /// The standard open() call:
30  ///    int open(const char *path, int oflag, ...);
31  Open,
32
33  /// The variant taking a directory file descriptor and a relative path:
34  ///    int openat(int fd, const char *path, int oflag, ...);
35  OpenAt
36};
37
38namespace {
39
40class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
41  mutable std::unique_ptr<BugTypeBT_openBT_pthreadOnce;
42  mutable Optional<uint64_tVal_O_CREAT;
43
44public:
45  DefaultBool CheckMisuseCheckPortability;
46
47  void checkPreStmt(const CallExpr *CECheckerContext &Cconst;
48
49  void CheckOpen(CheckerContext &Cconst CallExpr *CEconst;
50  void CheckOpenAt(CheckerContext &Cconst CallExpr *CEconst;
51  void CheckPthreadOnce(CheckerContext &Cconst CallExpr *CEconst;
52
53  void CheckOpenVariant(CheckerContext &C,
54                        const CallExpr *CEOpenVariant Variantconst;
55
56  void ReportOpenBug(CheckerContext &C,
57                     ProgramStateRef State,
58                     const char *Msg,
59                     SourceRange SRconst;
60
61};
62
63class UnixAPIPortabilityChecker : public Checkercheck::PreStmt<CallExpr> > {
64public:
65  void checkPreStmt(const CallExpr *CECheckerContext &Cconst;
66
67private:
68  mutable std::unique_ptr<BugTypeBT_mallocZero;
69
70  void CheckCallocZero(CheckerContext &Cconst CallExpr *CEconst;
71  void CheckMallocZero(CheckerContext &Cconst CallExpr *CEconst;
72  void CheckReallocZero(CheckerContext &Cconst CallExpr *CEconst;
73  void CheckReallocfZero(CheckerContext &Cconst CallExpr *CEconst;
74  void CheckAllocaZero(CheckerContext &Cconst CallExpr *CEconst;
75  void CheckAllocaWithAlignZero(CheckerContext &Cconst CallExpr *CEconst;
76  void CheckVallocZero(CheckerContext &Cconst CallExpr *CEconst;
77
78  bool ReportZeroByteAllocation(CheckerContext &C,
79                                ProgramStateRef falseState,
80                                const Expr *arg,
81                                const char *fn_nameconst;
82  void BasicAllocationCheck(CheckerContext &C,
83                            const CallExpr *CE,
84                            const unsigned numArgs,
85                            const unsigned sizeArg,
86                            const char *fnconst;
87};
88
89//end anonymous namespace
90
91static void LazyInitialize(const CheckerBase *Checker,
92                           std::unique_ptr<BugType> &BT,
93                           const char *name) {
94  if (BT)
95    return;
96  BT.reset(new BugType(Checker, name, categories::UnixAPI));
97}
98
99//===----------------------------------------------------------------------===//
100// "open" (man 2 open)
101//===----------------------------------------------------------------------===/
102
103void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE,
104                                        CheckerContext &Cconst {
105  const FunctionDecl *FD = C.getCalleeDecl(CE);
106  if (!FD || FD->getKind() != Decl::Function)
107    return;
108
109  // Don't treat functions in namespaces with the same name a Unix function
110  // as a call to the Unix function.
111  const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
112  if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
113    return;
114
115  StringRef FName = C.getCalleeName(FD);
116  if (FName.empty())
117    return;
118
119  if (FName == "open")
120    CheckOpen(CCE);
121
122  else if (FName == "openat")
123    CheckOpenAt(CCE);
124
125  else if (FName == "pthread_once")
126    CheckPthreadOnce(CCE);
127}
128void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
129                                         ProgramStateRef State,
130                                         const char *Msg,
131                                         SourceRange SRconst {
132  ExplodedNode *N = C.generateErrorNode(State);
133  if (!N)
134    return;
135
136  LazyInitialize(thisBT_open"Improper use of 'open'");
137
138  auto Report = llvm::make_unique<BugReport>(*BT_open, Msg, N);
139  Report->addRange(SR);
140  C.emitReport(std::move(Report));
141}
142
143void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
144                                     const CallExpr *CEconst {
145  CheckOpenVariant(CCEOpenVariant::Open);
146}
147
148void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
149                                       const CallExpr *CEconst {
150  CheckOpenVariant(CCEOpenVariant::OpenAt);
151}
152
153void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
154                                            const CallExpr *CE,
155                                            OpenVariant Variantconst {
156  // The index of the argument taking the flags open flags (O_RDONLY,
157  // O_WRONLY, O_CREAT, etc.),
158  unsigned int FlagsArgIndex;
159  const char *VariantName;
160  switch (Variant) {
161  case OpenVariant::Open:
162    FlagsArgIndex = 1;
163    VariantName = "open";
164    break;
165  case OpenVariant::OpenAt:
166    FlagsArgIndex = 2;
167    VariantName = "openat";
168    break;
169  };
170
171  // All calls should at least provide arguments up to the 'flags' parameter.
172  unsigned int MinArgCount = FlagsArgIndex + 1;
173
174  // If the flags has O_CREAT set then open/openat() require an additional
175  // argument specifying the file mode (permission bits) for the created file.
176  unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
177
178  // The create mode argument should be the last argument.
179  unsigned int MaxArgCount = CreateModeArgIndex + 1;
180
181  ProgramStateRef state = C.getState();
182
183  if (CE->getNumArgs() < MinArgCount) {
184    // The frontend should issue a warning for this case, so this is a sanity
185    // check.
186    return;
187  } else if (CE->getNumArgs() == MaxArgCount) {
188    const Expr *Arg = CE->getArg(CreateModeArgIndex);
189    QualType QT = Arg->getType();
190    if (!QT->isIntegerType()) {
191      SmallString<256SBuf;
192      llvm::raw_svector_ostream OS(SBuf);
193      OS << "The " << CreateModeArgIndex + 1
194         << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
195         << " argument to '" << VariantName << "' is not an integer";
196
197      ReportOpenBug(C, state,
198                    SBuf.c_str(),
199                    Arg->getSourceRange());
200      return;
201    }
202  } else if (CE->getNumArgs() > MaxArgCount) {
203    SmallString<256SBuf;
204    llvm::raw_svector_ostream OS(SBuf);
205    OS << "Call to '" << VariantName << "' with more than " << MaxArgCount
206       << " arguments";
207
208    ReportOpenBug(C, state,
209                  SBuf.c_str(),
210                  CE->getArg(MaxArgCount)->getSourceRange());
211    return;
212  }
213
214  // The definition of O_CREAT is platform specific.  We need a better way
215  // of querying this information from the checking environment.
216  if (!Val_O_CREAT.hasValue()) {
217    if (C.getASTContext().getTargetInfo().getTriple().getVendor()
218                                                      == llvm::Triple::Apple)
219      Val_O_CREAT = 0x0200;
220    else {
221      // FIXME: We need a more general way of getting the O_CREAT value.
222      // We could possibly grovel through the preprocessor state, but
223      // that would require passing the Preprocessor object to the ExprEngine.
224      // See also: MallocChecker.cpp / M_ZERO.
225      return;
226    }
227  }
228
229  // Now check if oflags has O_CREAT set.
230  const Expr *oflagsEx = CE->getArg(FlagsArgIndex);
231  const SVal V = C.getSVal(oflagsEx);
232  if (!V.getAs<NonLoc>()) {
233    // The case where 'V' can be a location can only be due to a bad header,
234    // so in this case bail out.
235    return;
236  }
237  NonLoc oflags = V.castAs<NonLoc>();
238  NonLoc ocreateFlag = C.getSValBuilder()
239      .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
240  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
241                                                      oflags, ocreateFlag,
242                                                      oflagsEx->getType());
243  if (maskedFlagsUC.isUnknownOrUndef())
244    return;
245  DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
246
247  // Check if maskedFlags is non-zero.
248  ProgramStateRef trueStatefalseState;
249  std::tie(trueState, falseState) = state->assume(maskedFlags);
250
251  // Only emit an error if the value of 'maskedFlags' is properly
252  // constrained;
253  if (!(trueState && !falseState))
254    return;
255
256  if (CE->getNumArgs() < MaxArgCount) {
257    SmallString<256SBuf;
258    llvm::raw_svector_ostream OS(SBuf);
259    OS << "Call to '" << VariantName << "' requires a "
260       << CreateModeArgIndex + 1
261       << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
262       << " argument when the 'O_CREAT' flag is set";
263    ReportOpenBug(C, trueState,
264                  SBuf.c_str(),
265                  oflagsEx->getSourceRange());
266  }
267}
268
269//===----------------------------------------------------------------------===//
270// pthread_once
271//===----------------------------------------------------------------------===//
272
273void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
274                                      const CallExpr *CEconst {
275
276  // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
277  // They can possibly be refactored.
278
279  if (CE->getNumArgs() < 1)
280    return;
281
282  // Check if the first argument is stack allocated.  If so, issue a warning
283  // because that's likely to be bad news.
284  ProgramStateRef state = C.getState();
285  const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion();
286  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
287    return;
288
289  ExplodedNode *N = C.generateErrorNode(state);
290  if (!N)
291    return;
292
293  SmallString<256S;
294  llvm::raw_svector_ostream os(S);
295  os << "Call to 'pthread_once' uses";
296  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
297    os << " the local variable '" << VR->getDecl()->getName() << '\'';
298  else
299    os << " stack allocated memory";
300  os << " for the \"control\" value.  Using such transient memory for "
301  "the control value is potentially dangerous.";
302  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
303    os << "  Perhaps you intended to declare the variable as 'static'?";
304
305  LazyInitialize(thisBT_pthreadOnce"Improper use of 'pthread_once'");
306
307  auto report = llvm::make_unique<BugReport>(*BT_pthreadOnce, os.str(), N);
308  report->addRange(CE->getArg(0)->getSourceRange());
309  C.emitReport(std::move(report));
310}
311
312//===----------------------------------------------------------------------===//
313// "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
314// with allocation size 0
315//===----------------------------------------------------------------------===//
316
317// FIXME: Eventually these should be rolled into the MallocChecker, but right now
318// they're more basic and valuable for widespread use.
319
320// Returns true if we try to do a zero byte allocation, false otherwise.
321// Fills in trueState and falseState.
322static bool IsZeroByteAllocation(ProgramStateRef state,
323                                 const SVal argVal,
324                                 ProgramStateRef *trueState,
325                                 ProgramStateRef *falseState) {
326  std::tie(*trueState, *falseState) =
327    state->assume(argVal.castAs<DefinedSVal>());
328
329  return (*falseState && !*trueState);
330}
331
332// Generates an error report, indicating that the function whose name is given
333// will perform a zero byte allocation.
334// Returns false if an error occurred, true otherwise.
335bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
336                                                    CheckerContext &C,
337                                                    ProgramStateRef falseState,
338                                                    const Expr *arg,
339                                                    const char *fn_nameconst {
340  ExplodedNode *N = C.generateErrorNode(falseState);
341  if (!N)
342    return false;
343
344  LazyInitialize(thisBT_mallocZero,
345                 "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
346
347  SmallString<256S;
348  llvm::raw_svector_ostream os(S);
349  os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
350  auto report = llvm::make_unique<BugReport>(*BT_mallocZero, os.str(), N);
351
352  report->addRange(arg->getSourceRange());
353  bugreporter::trackExpressionValue(N, arg, *report);
354  C.emitReport(std::move(report));
355
356  return true;
357}
358
359// Does a basic check for 0-sized allocations suitable for most of the below
360// functions (modulo "calloc")
361void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
362                                                     const CallExpr *CE,
363                                                     const unsigned numArgs,
364                                                     const unsigned sizeArg,
365                                                     const char *fnconst {
366  // Sanity check for the correct number of arguments
367  if (CE->getNumArgs() != numArgs)
368    return;
369
370  // Check if the allocation size is 0.
371  ProgramStateRef state = C.getState();
372  ProgramStateRef trueState = nullptrfalseState = nullptr;
373  const Expr *arg = CE->getArg(sizeArg);
374  SVal argVal = C.getSVal(arg);
375
376  if (argVal.isUnknownOrUndef())
377    return;
378
379  // Is the value perfectly constrained to zero?
380  if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
381    (void) ReportZeroByteAllocation(C, falseState, arg, fn);
382    return;
383  }
384  // Assume the value is non-zero going forward.
385  assert(trueState);
386  if (trueState != state)
387    C.addTransition(trueState);
388}
389
390void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
391                                                const CallExpr *CEconst {
392  unsigned int nArgs = CE->getNumArgs();
393  if (nArgs != 2)
394    return;
395
396  ProgramStateRef state = C.getState();
397  ProgramStateRef trueState = nullptrfalseState = nullptr;
398
399  unsigned int i;
400  for (i = 0i < nArgsi++) {
401    const Expr *arg = CE->getArg(i);
402    SVal argVal = C.getSVal(arg);
403    if (argVal.isUnknownOrUndef()) {
404      if (i == 0)
405        continue;
406      else
407        return;
408    }
409
410    if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
411      if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
412        return;
413      else if (i == 0)
414        continue;
415      else
416        return;
417    }
418  }
419
420  // Assume the value is non-zero going forward.
421  assert(trueState);
422  if (trueState != state)
423    C.addTransition(trueState);
424}
425
426void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
427                                                const CallExpr *CEconst {
428  BasicAllocationCheck(CCE10"malloc");
429}
430
431void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
432                                                 const CallExpr *CEconst {
433  BasicAllocationCheck(CCE21"realloc");
434}
435
436void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
437                                                  const CallExpr *CEconst {
438  BasicAllocationCheck(CCE21"reallocf");
439}
440
441void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
442                                                const CallExpr *CEconst {
443  BasicAllocationCheck(CCE10"alloca");
444}
445
446void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
447                                                     CheckerContext &C,
448                                                     const CallExpr *CEconst {
449  BasicAllocationCheck(CCE20"__builtin_alloca_with_align");
450}
451
452void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
453                                                const CallExpr *CEconst {
454  BasicAllocationCheck(CCE10"valloc");
455}
456
457void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
458                                             CheckerContext &Cconst {
459  const FunctionDecl *FD = C.getCalleeDecl(CE);
460  if (!FD || FD->getKind() != Decl::Function)
461    return;
462
463  // Don't treat functions in namespaces with the same name a Unix function
464  // as a call to the Unix function.
465  const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
466  if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
467    return;
468
469  StringRef FName = C.getCalleeName(FD);
470  if (FName.empty())
471    return;
472
473  if (FName == "calloc")
474    CheckCallocZero(CCE);
475
476  else if (FName == "malloc")
477    CheckMallocZero(CCE);
478
479  else if (FName == "realloc")
480    CheckReallocZero(CCE);
481
482  else if (FName == "reallocf")
483    CheckReallocfZero(CCE);
484
485  else if (FName == "alloca" || FName ==  "__builtin_alloca")
486    CheckAllocaZero(CCE);
487
488  else if (FName == "__builtin_alloca_with_align")
489    CheckAllocaWithAlignZero(CCE);
490
491  else if (FName == "valloc")
492    CheckVallocZero(CCE);
493}
494
495//===----------------------------------------------------------------------===//
496// Registration.
497//===----------------------------------------------------------------------===//
498
499#define REGISTER_CHECKER(CHECKERNAME)                                          \
500  void ento::register##CHECKERNAME(CheckerManager &mgr) {                      \
501    mgr.registerChecker<CHECKERNAME>();                                        \
502  }                                                                            \
503                                                                               \
504  bool ento::shouldRegister##CHECKERNAME(const LangOptions &LO) {              \
505    return true;                                                               \
506  }
507
508REGISTER_CHECKER(UnixAPIMisuseChecker)
509REGISTER_CHECKER(UnixAPIPortabilityChecker)
510