clang  15.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  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
47 
48  void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
49  void CheckOpenAt(CheckerContext &C, const CallExpr *CE) const;
50  void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
51 
52  void CheckOpenVariant(CheckerContext &C,
53  const CallExpr *CE, OpenVariant Variant) const;
54 
55  void ReportOpenBug(CheckerContext &C,
57  const char *Msg,
58  SourceRange SR) const;
59 
60 };
61 
62 class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
63 public:
64  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
65 
66 private:
67  mutable std::unique_ptr<BugType> BT_mallocZero;
68 
69  void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
70  void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
71  void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
72  void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
73  void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
74  void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const;
75  void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
76 
77  bool ReportZeroByteAllocation(CheckerContext &C,
78  ProgramStateRef falseState,
79  const Expr *arg,
80  const char *fn_name) const;
81  void BasicAllocationCheck(CheckerContext &C,
82  const CallExpr *CE,
83  const unsigned numArgs,
84  const unsigned sizeArg,
85  const char *fn) const;
86 };
87 
88 } //end anonymous namespace
89 
90 static void LazyInitialize(const CheckerBase *Checker,
91  std::unique_ptr<BugType> &BT,
92  const char *name) {
93  if (BT)
94  return;
95  BT.reset(new BugType(Checker, name, categories::UnixAPI));
96 }
97 
98 //===----------------------------------------------------------------------===//
99 // "open" (man 2 open)
100 //===----------------------------------------------------------------------===/
101 
102 void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE,
103  CheckerContext &C) const {
104  const FunctionDecl *FD = C.getCalleeDecl(CE);
105  if (!FD || FD->getKind() != Decl::Function)
106  return;
107 
108  // Don't treat functions in namespaces with the same name a Unix function
109  // as a call to the Unix function.
110  const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
111  if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx))
112  return;
113 
114  StringRef FName = C.getCalleeName(FD);
115  if (FName.empty())
116  return;
117 
118  if (FName == "open")
119  CheckOpen(C, CE);
120 
121  else if (FName == "openat")
122  CheckOpenAt(C, CE);
123 
124  else if (FName == "pthread_once")
125  CheckPthreadOnce(C, CE);
126 }
127 void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
129  const char *Msg,
130  SourceRange SR) const {
131  ExplodedNode *N = C.generateErrorNode(State);
132  if (!N)
133  return;
134 
135  LazyInitialize(this, BT_open, "Improper use of 'open'");
136 
137  auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
138  Report->addRange(SR);
139  C.emitReport(std::move(Report));
140 }
141 
142 void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
143  const CallExpr *CE) const {
144  CheckOpenVariant(C, CE, OpenVariant::Open);
145 }
146 
147 void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
148  const CallExpr *CE) const {
149  CheckOpenVariant(C, CE, OpenVariant::OpenAt);
150 }
151 
152 void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
153  const CallExpr *CE,
154  OpenVariant Variant) const {
155  // The index of the argument taking the flags open flags (O_RDONLY,
156  // O_WRONLY, O_CREAT, etc.),
157  unsigned int FlagsArgIndex;
158  const char *VariantName;
159  switch (Variant) {
160  case OpenVariant::Open:
161  FlagsArgIndex = 1;
162  VariantName = "open";
163  break;
164  case OpenVariant::OpenAt:
165  FlagsArgIndex = 2;
166  VariantName = "openat";
167  break;
168  };
169 
170  // All calls should at least provide arguments up to the 'flags' parameter.
171  unsigned int MinArgCount = FlagsArgIndex + 1;
172 
173  // If the flags has O_CREAT set then open/openat() require an additional
174  // argument specifying the file mode (permission bits) for the created file.
175  unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
176 
177  // The create mode argument should be the last argument.
178  unsigned int MaxArgCount = CreateModeArgIndex + 1;
179 
180  ProgramStateRef state = C.getState();
181 
182  if (CE->getNumArgs() < MinArgCount) {
183  // The frontend should issue a warning for this case. Just return.
184  return;
185  } else if (CE->getNumArgs() == MaxArgCount) {
186  const Expr *Arg = CE->getArg(CreateModeArgIndex);
187  QualType QT = Arg->getType();
188  if (!QT->isIntegerType()) {
189  SmallString<256> SBuf;
190  llvm::raw_svector_ostream OS(SBuf);
191  OS << "The " << CreateModeArgIndex + 1
192  << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
193  << " argument to '" << VariantName << "' is not an integer";
194 
195  ReportOpenBug(C, state,
196  SBuf.c_str(),
197  Arg->getSourceRange());
198  return;
199  }
200  } else if (CE->getNumArgs() > MaxArgCount) {
201  SmallString<256> SBuf;
202  llvm::raw_svector_ostream OS(SBuf);
203  OS << "Call to '" << VariantName << "' with more than " << MaxArgCount
204  << " arguments";
205 
206  ReportOpenBug(C, state,
207  SBuf.c_str(),
208  CE->getArg(MaxArgCount)->getSourceRange());
209  return;
210  }
211 
212  // The definition of O_CREAT is platform specific. We need a better way
213  // of querying this information from the checking environment.
214  if (!Val_O_CREAT) {
215  if (C.getASTContext().getTargetInfo().getTriple().getVendor()
216  == llvm::Triple::Apple)
217  Val_O_CREAT = 0x0200;
218  else {
219  // FIXME: We need a more general way of getting the O_CREAT value.
220  // We could possibly grovel through the preprocessor state, but
221  // that would require passing the Preprocessor object to the ExprEngine.
222  // See also: MallocChecker.cpp / M_ZERO.
223  return;
224  }
225  }
226 
227  // Now check if oflags has O_CREAT set.
228  const Expr *oflagsEx = CE->getArg(FlagsArgIndex);
229  const SVal V = C.getSVal(oflagsEx);
230  if (!isa<NonLoc>(V)) {
231  // The case where 'V' can be a location can only be due to a bad header,
232  // so in this case bail out.
233  return;
234  }
235  NonLoc oflags = V.castAs<NonLoc>();
236  NonLoc ocreateFlag = C.getSValBuilder()
237  .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
238  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
239  oflags, ocreateFlag,
240  oflagsEx->getType());
241  if (maskedFlagsUC.isUnknownOrUndef())
242  return;
243  DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
244 
245  // Check if maskedFlags is non-zero.
246  ProgramStateRef trueState, falseState;
247  std::tie(trueState, falseState) = state->assume(maskedFlags);
248 
249  // Only emit an error if the value of 'maskedFlags' is properly
250  // constrained;
251  if (!(trueState && !falseState))
252  return;
253 
254  if (CE->getNumArgs() < MaxArgCount) {
255  SmallString<256> SBuf;
256  llvm::raw_svector_ostream OS(SBuf);
257  OS << "Call to '" << VariantName << "' requires a "
258  << CreateModeArgIndex + 1
259  << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
260  << " argument when the 'O_CREAT' flag is set";
261  ReportOpenBug(C, trueState,
262  SBuf.c_str(),
263  oflagsEx->getSourceRange());
264  }
265 }
266 
267 //===----------------------------------------------------------------------===//
268 // pthread_once
269 //===----------------------------------------------------------------------===//
270 
271 void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
272  const CallExpr *CE) const {
273 
274  // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
275  // They can possibly be refactored.
276 
277  if (CE->getNumArgs() < 1)
278  return;
279 
280  // Check if the first argument is stack allocated. If so, issue a warning
281  // because that's likely to be bad news.
282  ProgramStateRef state = C.getState();
283  const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion();
284  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
285  return;
286 
287  ExplodedNode *N = C.generateErrorNode(state);
288  if (!N)
289  return;
290 
292  llvm::raw_svector_ostream os(S);
293  os << "Call to 'pthread_once' uses";
294  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
295  os << " the local variable '" << VR->getDecl()->getName() << '\'';
296  else
297  os << " stack allocated memory";
298  os << " for the \"control\" value. Using such transient memory for "
299  "the control value is potentially dangerous.";
300  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
301  os << " Perhaps you intended to declare the variable as 'static'?";
302 
303  LazyInitialize(this, BT_pthreadOnce, "Improper use of 'pthread_once'");
304 
305  auto report =
306  std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N);
307  report->addRange(CE->getArg(0)->getSourceRange());
308  C.emitReport(std::move(report));
309 }
310 
311 //===----------------------------------------------------------------------===//
312 // "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
313 // with allocation size 0
314 //===----------------------------------------------------------------------===//
315 
316 // FIXME: Eventually these should be rolled into the MallocChecker, but right now
317 // they're more basic and valuable for widespread use.
318 
319 // Returns true if we try to do a zero byte allocation, false otherwise.
320 // Fills in trueState and falseState.
322  const SVal argVal,
323  ProgramStateRef *trueState,
324  ProgramStateRef *falseState) {
325  std::tie(*trueState, *falseState) =
326  state->assume(argVal.castAs<DefinedSVal>());
327 
328  return (*falseState && !*trueState);
329 }
330 
331 // Generates an error report, indicating that the function whose name is given
332 // will perform a zero byte allocation.
333 // Returns false if an error occurred, true otherwise.
334 bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
335  CheckerContext &C,
336  ProgramStateRef falseState,
337  const Expr *arg,
338  const char *fn_name) const {
339  ExplodedNode *N = C.generateErrorNode(falseState);
340  if (!N)
341  return false;
342 
343  LazyInitialize(this, BT_mallocZero,
344  "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
345 
347  llvm::raw_svector_ostream os(S);
348  os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
349  auto report =
350  std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
351 
352  report->addRange(arg->getSourceRange());
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")
361 void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
362  const CallExpr *CE,
363  const unsigned numArgs,
364  const unsigned sizeArg,
365  const char *fn) const {
366  // 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 = nullptr, falseState = 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 
390 void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
391  const CallExpr *CE) const {
392  unsigned int nArgs = CE->getNumArgs();
393  if (nArgs != 2)
394  return;
395 
396  ProgramStateRef state = C.getState();
397  ProgramStateRef trueState = nullptr, falseState = nullptr;
398 
399  unsigned int i;
400  for (i = 0; i < nArgs; i++) {
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 
426 void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
427  const CallExpr *CE) const {
428  BasicAllocationCheck(C, CE, 1, 0, "malloc");
429 }
430 
431 void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
432  const CallExpr *CE) const {
433  BasicAllocationCheck(C, CE, 2, 1, "realloc");
434 }
435 
436 void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
437  const CallExpr *CE) const {
438  BasicAllocationCheck(C, CE, 2, 1, "reallocf");
439 }
440 
441 void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
442  const CallExpr *CE) const {
443  BasicAllocationCheck(C, CE, 1, 0, "alloca");
444 }
445 
446 void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
447  CheckerContext &C,
448  const CallExpr *CE) const {
449  BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align");
450 }
451 
452 void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
453  const CallExpr *CE) const {
454  BasicAllocationCheck(C, CE, 1, 0, "valloc");
455 }
456 
457 void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
458  CheckerContext &C) const {
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 (isa_and_nonnull<NamespaceDecl>(NamespaceCtx))
467  return;
468 
469  StringRef FName = C.getCalleeName(FD);
470  if (FName.empty())
471  return;
472 
473  if (FName == "calloc")
474  CheckCallocZero(C, CE);
475 
476  else if (FName == "malloc")
477  CheckMallocZero(C, CE);
478 
479  else if (FName == "realloc")
480  CheckReallocZero(C, CE);
481 
482  else if (FName == "reallocf")
483  CheckReallocfZero(C, CE);
484 
485  else if (FName == "alloca" || FName == "__builtin_alloca")
486  CheckAllocaZero(C, CE);
487 
488  else if (FName == "__builtin_alloca_with_align")
489  CheckAllocaWithAlignZero(C, CE);
490 
491  else if (FName == "valloc")
492  CheckVallocZero(C, CE);
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 CheckerManager &mgr) { \
505  return true; \
506  }
507 
508 REGISTER_CHECKER(UnixAPIMisuseChecker)
509 REGISTER_CHECKER(UnixAPIPortabilityChecker)
LazyInitialize
static void LazyInitialize(const CheckerBase *Checker, std::unique_ptr< BugType > &BT, const char *name)
Definition: UnixAPIChecker.cpp:90
OpenVariant
OpenVariant
Definition: UnixAPIChecker.cpp:29
clang::SourceRange
A trivial tuple used to represent a source range.
Definition: SourceLocation.h:210
clang::DeclContext
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1376
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:731
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:55
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:499
V
#define V(N, I)
Definition: ASTContext.h:3176
IsZeroByteAllocation
static bool IsZeroByteAllocation(ProgramStateRef state, const SVal argVal, ProgramStateRef *trueState, ProgramStateRef *falseState)
Definition: UnixAPIChecker.cpp:321
BuiltinCheckerRegistration.h
clang::Decl::getKind
Kind getKind() const
Definition: DeclBase.h:435
clang::DeclContext::getEnclosingNamespaceContext
DeclContext * getEnclosingNamespaceContext()
Retrieve the nearest enclosing namespace context.
Definition: DeclBase.cpp:1815
CheckerManager.h
clang::CallExpr::getArg
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2992
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:2979
State
LineState State
Definition: UnwrappedLineFormatter.cpp:1126
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:7128
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:1872
clang::CallExpr
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2801
clang::ento::ObjKind::OS
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...