clang  14.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 (isa_and_nonnull<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());
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 (isa_and_nonnull<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)
LazyInitialize
static void LazyInitialize(const CheckerBase *Checker, std::unique_ptr< BugType > &BT, const char *name)
Definition: UnixAPIChecker.cpp:92
OpenVariant
OpenVariant
Definition: UnixAPIChecker.cpp:29
clang::SourceRange
A trivial tuple used to represent a source range.
Definition: SourceLocation.h:212
clang::DeclContext
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1347
OpenVariant::OpenAt
@ OpenAt
The variant taking a directory file descriptor and a relative path: int openat(int fd,...
TargetInfo.h
clang::Stmt::getSourceRange
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:324
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:673
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
OpenVariant::Open
@ Open
The standard open() call: int open(const char *path, int oflag, ...);.
llvm::Optional< uint64_t >
REGISTER_CHECKER
#define REGISTER_CHECKER(CHECKERNAME)
Definition: UnixAPIChecker.cpp:502
V
#define V(N, I)
Definition: ASTContext.h:3121
IsZeroByteAllocation
static bool IsZeroByteAllocation(ProgramStateRef state, const SVal argVal, ProgramStateRef *trueState, ProgramStateRef *falseState)
Definition: UnixAPIChecker.cpp:324
BuiltinCheckerRegistration.h
clang::Decl::getKind
Kind getKind() const
Definition: DeclBase.h:433
clang::DeclContext::getEnclosingNamespaceContext
DeclContext * getEnclosingNamespaceContext()
Retrieve the nearest enclosing namespace context.
Definition: DeclBase.cpp:1798
CheckerManager.h
clang::CallExpr::getArg
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2986
llvm::SmallString
Definition: LLVM.h:37
state
and static some checkers Checker The latter are built on top of the former via the Checker and CheckerVisitor and attempts to isolate them from much of the gore of the internal analysis the analyzer is basically a source code simulator that traces out possible paths of execution The state of the and the combination of state and program point is a node in an exploded which has the entry program point and initial state
Definition: README.txt:30
clang::ento::bugreporter::trackExpressionValue
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
BugType.h
clang::CallExpr::getNumArgs
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2973
State
LineState State
Definition: UnwrappedLineFormatter.cpp:986
CheckerContext.h
Checker.h
clang
Definition: CalledOnceCheck.h:17
std::arg
__DEVICE__ _Tp arg(const std::complex< _Tp > &__c)
Definition: complex_cmath.h:40
clang::Expr::getType
QualType getType() const
Definition: Expr.h:141
clang::Type::isIntegerType
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:6987
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::transformer::name
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
Definition: RangeSelector.cpp:200
clang::ento::categories::UnixAPI
const char *const UnixAPI
Definition: CommonBugCategories.cpp:21
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1856
clang::CallExpr
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2795
clang::ento::ObjKind::OS
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...