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