clang  10.0.0svn
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/Support/raw_ostream.h"
24 
25 using namespace clang;
26 using namespace ento;
27 
28 enum 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 
38 namespace {
39 
40 class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
41  mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
42  mutable Optional<uint64_t> Val_O_CREAT;
43 
44 public:
45  DefaultBool CheckMisuse, CheckPortability;
46 
47  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
48 
49  void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
50  void CheckOpenAt(CheckerContext &C, const CallExpr *CE) const;
51  void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
52 
53  void CheckOpenVariant(CheckerContext &C,
54  const CallExpr *CE, OpenVariant Variant) const;
55 
56  void ReportOpenBug(CheckerContext &C,
58  const char *Msg,
59  SourceRange SR) const;
60 
61 };
62 
63 class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
64 public:
65  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
66 
67 private:
68  mutable std::unique_ptr<BugType> BT_mallocZero;
69 
70  void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
71  void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
72  void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
73  void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
74  void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
75  void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const;
76  void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
77 
78  bool ReportZeroByteAllocation(CheckerContext &C,
79  ProgramStateRef falseState,
80  const Expr *arg,
81  const char *fn_name) const;
82  void BasicAllocationCheck(CheckerContext &C,
83  const CallExpr *CE,
84  const unsigned numArgs,
85  const unsigned sizeArg,
86  const char *fn) const;
87 };
88 
89 } //end anonymous namespace
90 
91 static 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 
103 void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE,
104  CheckerContext &C) const {
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(C, CE);
121 
122  else if (FName == "openat")
123  CheckOpenAt(C, CE);
124 
125  else if (FName == "pthread_once")
126  CheckPthreadOnce(C, CE);
127 }
128 void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
130  const char *Msg,
131  SourceRange SR) const {
132  ExplodedNode *N = C.generateErrorNode(State);
133  if (!N)
134  return;
135 
136  LazyInitialize(this, BT_open, "Improper use of 'open'");
137 
138  auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
139  Report->addRange(SR);
140  C.emitReport(std::move(Report));
141 }
142 
143 void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
144  const CallExpr *CE) const {
145  CheckOpenVariant(C, CE, OpenVariant::Open);
146 }
147 
148 void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
149  const CallExpr *CE) const {
150  CheckOpenVariant(C, CE, OpenVariant::OpenAt);
151 }
152 
153 void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
154  const CallExpr *CE,
155  OpenVariant Variant) const {
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<256> SBuf;
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<256> SBuf;
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 trueState, falseState;
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<256> SBuf;
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 
273 void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
274  const CallExpr *CE) const {
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 
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(this, BT_pthreadOnce, "Improper use of 'pthread_once'");
306 
307  auto report =
308  std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N);
309  report->addRange(CE->getArg(0)->getSourceRange());
310  C.emitReport(std::move(report));
311 }
312 
313 //===----------------------------------------------------------------------===//
314 // "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
315 // with allocation size 0
316 //===----------------------------------------------------------------------===//
317 
318 // FIXME: Eventually these should be rolled into the MallocChecker, but right now
319 // they're more basic and valuable for widespread use.
320 
321 // Returns true if we try to do a zero byte allocation, false otherwise.
322 // Fills in trueState and falseState.
324  const SVal argVal,
325  ProgramStateRef *trueState,
326  ProgramStateRef *falseState) {
327  std::tie(*trueState, *falseState) =
328  state->assume(argVal.castAs<DefinedSVal>());
329 
330  return (*falseState && !*trueState);
331 }
332 
333 // Generates an error report, indicating that the function whose name is given
334 // will perform a zero byte allocation.
335 // Returns false if an error occurred, true otherwise.
336 bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
337  CheckerContext &C,
338  ProgramStateRef falseState,
339  const Expr *arg,
340  const char *fn_name) const {
341  ExplodedNode *N = C.generateErrorNode(falseState);
342  if (!N)
343  return false;
344 
345  LazyInitialize(this, BT_mallocZero,
346  "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
347 
349  llvm::raw_svector_ostream os(S);
350  os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
351  auto report =
352  std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
353 
354  report->addRange(arg->getSourceRange());
355  bugreporter::trackExpressionValue(N, arg, *report);
356  C.emitReport(std::move(report));
357 
358  return true;
359 }
360 
361 // Does a basic check for 0-sized allocations suitable for most of the below
362 // functions (modulo "calloc")
363 void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
364  const CallExpr *CE,
365  const unsigned numArgs,
366  const unsigned sizeArg,
367  const char *fn) const {
368  // Sanity check for the correct number of arguments
369  if (CE->getNumArgs() != numArgs)
370  return;
371 
372  // Check if the allocation size is 0.
373  ProgramStateRef state = C.getState();
374  ProgramStateRef trueState = nullptr, falseState = nullptr;
375  const Expr *arg = CE->getArg(sizeArg);
376  SVal argVal = C.getSVal(arg);
377 
378  if (argVal.isUnknownOrUndef())
379  return;
380 
381  // Is the value perfectly constrained to zero?
382  if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
383  (void) ReportZeroByteAllocation(C, falseState, arg, fn);
384  return;
385  }
386  // Assume the value is non-zero going forward.
387  assert(trueState);
388  if (trueState != state)
389  C.addTransition(trueState);
390 }
391 
392 void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
393  const CallExpr *CE) const {
394  unsigned int nArgs = CE->getNumArgs();
395  if (nArgs != 2)
396  return;
397 
398  ProgramStateRef state = C.getState();
399  ProgramStateRef trueState = nullptr, falseState = nullptr;
400 
401  unsigned int i;
402  for (i = 0; i < nArgs; i++) {
403  const Expr *arg = CE->getArg(i);
404  SVal argVal = C.getSVal(arg);
405  if (argVal.isUnknownOrUndef()) {
406  if (i == 0)
407  continue;
408  else
409  return;
410  }
411 
412  if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
413  if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
414  return;
415  else if (i == 0)
416  continue;
417  else
418  return;
419  }
420  }
421 
422  // Assume the value is non-zero going forward.
423  assert(trueState);
424  if (trueState != state)
425  C.addTransition(trueState);
426 }
427 
428 void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
429  const CallExpr *CE) const {
430  BasicAllocationCheck(C, CE, 1, 0, "malloc");
431 }
432 
433 void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
434  const CallExpr *CE) const {
435  BasicAllocationCheck(C, CE, 2, 1, "realloc");
436 }
437 
438 void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
439  const CallExpr *CE) const {
440  BasicAllocationCheck(C, CE, 2, 1, "reallocf");
441 }
442 
443 void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
444  const CallExpr *CE) const {
445  BasicAllocationCheck(C, CE, 1, 0, "alloca");
446 }
447 
448 void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
449  CheckerContext &C,
450  const CallExpr *CE) const {
451  BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align");
452 }
453 
454 void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
455  const CallExpr *CE) const {
456  BasicAllocationCheck(C, CE, 1, 0, "valloc");
457 }
458 
459 void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
460  CheckerContext &C) const {
461  const FunctionDecl *FD = C.getCalleeDecl(CE);
462  if (!FD || FD->getKind() != Decl::Function)
463  return;
464 
465  // Don't treat functions in namespaces with the same name a Unix function
466  // as a call to the Unix function.
467  const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
468  if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
469  return;
470 
471  StringRef FName = C.getCalleeName(FD);
472  if (FName.empty())
473  return;
474 
475  if (FName == "calloc")
476  CheckCallocZero(C, CE);
477 
478  else if (FName == "malloc")
479  CheckMallocZero(C, CE);
480 
481  else if (FName == "realloc")
482  CheckReallocZero(C, CE);
483 
484  else if (FName == "reallocf")
485  CheckReallocfZero(C, CE);
486 
487  else if (FName == "alloca" || FName == "__builtin_alloca")
488  CheckAllocaZero(C, CE);
489 
490  else if (FName == "__builtin_alloca_with_align")
491  CheckAllocaWithAlignZero(C, CE);
492 
493  else if (FName == "valloc")
494  CheckVallocZero(C, CE);
495 }
496 
497 //===----------------------------------------------------------------------===//
498 // Registration.
499 //===----------------------------------------------------------------------===//
500 
501 #define REGISTER_CHECKER(CHECKERNAME) \
502  void ento::register##CHECKERNAME(CheckerManager &mgr) { \
503  mgr.registerChecker<CHECKERNAME>(); \
504  } \
505  \
506  bool ento::shouldRegister##CHECKERNAME(const LangOptions &LO) { \
507  return true; \
508  }
509 
510 REGISTER_CHECKER(UnixAPIMisuseChecker)
511 REGISTER_CHECKER(UnixAPIPortabilityChecker)
Represents a function declaration or definition.
Definition: Decl.h:1784
A (possibly-)qualified type.
Definition: Type.h:643
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2677
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2664
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
constexpr XRayInstrMask Function
Definition: XRayInstr.h:38
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr or CxxCtorInitializer) selects the name&#39;s to...
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:1762
static void LazyInitialize(const CheckerBase *Checker, std::unique_ptr< BugType > &BT, const char *name)
This represents one expression.
Definition: Expr.h:108
static bool IsZeroByteAllocation(ProgramStateRef state, const SVal argVal, ProgramStateRef *trueState, ProgramStateRef *falseState)
#define V(N, I)
Definition: ASTContext.h:2921
QualType getType() const
Definition: Expr.h:137
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:1271
Kind getKind() const
Definition: DeclBase.h:432
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:6684
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:262
Defines the clang::TargetInfo interface.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2521
#define REGISTER_CHECKER(CHECKERNAME)
OpenVariant
A trivial tuple used to represent a source range.