clang  16.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.value(), oflagsEx->getType())
238  .castAs<NonLoc>();
239  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
240  oflags, ocreateFlag,
241  oflagsEx->getType());
242  if (maskedFlagsUC.isUnknownOrUndef())
243  return;
244  DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
245 
246  // Check if maskedFlags is non-zero.
247  ProgramStateRef trueState, falseState;
248  std::tie(trueState, falseState) = state->assume(maskedFlags);
249 
250  // Only emit an error if the value of 'maskedFlags' is properly
251  // constrained;
252  if (!(trueState && !falseState))
253  return;
254 
255  if (CE->getNumArgs() < MaxArgCount) {
256  SmallString<256> SBuf;
257  llvm::raw_svector_ostream OS(SBuf);
258  OS << "Call to '" << VariantName << "' requires a "
259  << CreateModeArgIndex + 1
260  << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
261  << " argument when the 'O_CREAT' flag is set";
262  ReportOpenBug(C, trueState,
263  SBuf.c_str(),
264  oflagsEx->getSourceRange());
265  }
266 }
267 
268 //===----------------------------------------------------------------------===//
269 // pthread_once
270 //===----------------------------------------------------------------------===//
271 
272 void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
273  const CallExpr *CE) const {
274 
275  // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
276  // They can possibly be refactored.
277 
278  if (CE->getNumArgs() < 1)
279  return;
280 
281  // Check if the first argument is stack allocated. If so, issue a warning
282  // because that's likely to be bad news.
283  ProgramStateRef state = C.getState();
284  const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion();
285  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
286  return;
287 
288  ExplodedNode *N = C.generateErrorNode(state);
289  if (!N)
290  return;
291 
293  llvm::raw_svector_ostream os(S);
294  os << "Call to 'pthread_once' uses";
295  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
296  os << " the local variable '" << VR->getDecl()->getName() << '\'';
297  else
298  os << " stack allocated memory";
299  os << " for the \"control\" value. Using such transient memory for "
300  "the control value is potentially dangerous.";
301  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
302  os << " Perhaps you intended to declare the variable as 'static'?";
303 
304  LazyInitialize(this, BT_pthreadOnce, "Improper use of 'pthread_once'");
305 
306  auto report =
307  std::make_unique<PathSensitiveBugReport>(*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.
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.
335 bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
336  CheckerContext &C,
337  ProgramStateRef falseState,
338  const Expr *arg,
339  const char *fn_name) const {
340  ExplodedNode *N = C.generateErrorNode(falseState);
341  if (!N)
342  return false;
343 
344  LazyInitialize(this, BT_mallocZero,
345  "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
346 
348  llvm::raw_svector_ostream os(S);
349  os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
350  auto report =
351  std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
352 
353  report->addRange(arg->getSourceRange());
355  C.emitReport(std::move(report));
356 
357  return true;
358 }
359 
360 // Does a basic check for 0-sized allocations suitable for most of the below
361 // functions (modulo "calloc")
362 void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
363  const CallExpr *CE,
364  const unsigned numArgs,
365  const unsigned sizeArg,
366  const char *fn) const {
367  // Check for the correct number of arguments.
368  if (CE->getNumArgs() != numArgs)
369  return;
370 
371  // Check if the allocation size is 0.
372  ProgramStateRef state = C.getState();
373  ProgramStateRef trueState = nullptr, falseState = nullptr;
374  const Expr *arg = CE->getArg(sizeArg);
375  SVal argVal = C.getSVal(arg);
376 
377  if (argVal.isUnknownOrUndef())
378  return;
379 
380  // Is the value perfectly constrained to zero?
381  if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
382  (void) ReportZeroByteAllocation(C, falseState, arg, fn);
383  return;
384  }
385  // Assume the value is non-zero going forward.
386  assert(trueState);
387  if (trueState != state)
388  C.addTransition(trueState);
389 }
390 
391 void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
392  const CallExpr *CE) const {
393  unsigned int nArgs = CE->getNumArgs();
394  if (nArgs != 2)
395  return;
396 
397  ProgramStateRef state = C.getState();
398  ProgramStateRef trueState = nullptr, falseState = nullptr;
399 
400  unsigned int i;
401  for (i = 0; i < nArgs; i++) {
402  const Expr *arg = CE->getArg(i);
403  SVal argVal = C.getSVal(arg);
404  if (argVal.isUnknownOrUndef()) {
405  if (i == 0)
406  continue;
407  else
408  return;
409  }
410 
411  if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
412  if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
413  return;
414  else if (i == 0)
415  continue;
416  else
417  return;
418  }
419  }
420 
421  // Assume the value is non-zero going forward.
422  assert(trueState);
423  if (trueState != state)
424  C.addTransition(trueState);
425 }
426 
427 void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
428  const CallExpr *CE) const {
429  BasicAllocationCheck(C, CE, 1, 0, "malloc");
430 }
431 
432 void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
433  const CallExpr *CE) const {
434  BasicAllocationCheck(C, CE, 2, 1, "realloc");
435 }
436 
437 void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
438  const CallExpr *CE) const {
439  BasicAllocationCheck(C, CE, 2, 1, "reallocf");
440 }
441 
442 void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
443  const CallExpr *CE) const {
444  BasicAllocationCheck(C, CE, 1, 0, "alloca");
445 }
446 
447 void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
448  CheckerContext &C,
449  const CallExpr *CE) const {
450  BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align");
451 }
452 
453 void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
454  const CallExpr *CE) const {
455  BasicAllocationCheck(C, CE, 1, 0, "valloc");
456 }
457 
458 void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
459  CheckerContext &C) const {
460  const FunctionDecl *FD = C.getCalleeDecl(CE);
461  if (!FD || FD->getKind() != Decl::Function)
462  return;
463 
464  // Don't treat functions in namespaces with the same name a Unix function
465  // as a call to the Unix function.
466  const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
467  if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx))
468  return;
469 
470  StringRef FName = C.getCalleeName(FD);
471  if (FName.empty())
472  return;
473 
474  if (FName == "calloc")
475  CheckCallocZero(C, CE);
476 
477  else if (FName == "malloc")
478  CheckMallocZero(C, CE);
479 
480  else if (FName == "realloc")
481  CheckReallocZero(C, CE);
482 
483  else if (FName == "reallocf")
484  CheckReallocfZero(C, CE);
485 
486  else if (FName == "alloca" || FName == "__builtin_alloca")
487  CheckAllocaZero(C, CE);
488 
489  else if (FName == "__builtin_alloca_with_align")
490  CheckAllocaWithAlignZero(C, CE);
491 
492  else if (FName == "valloc")
493  CheckVallocZero(C, CE);
494 }
495 
496 //===----------------------------------------------------------------------===//
497 // Registration.
498 //===----------------------------------------------------------------------===//
499 
500 #define REGISTER_CHECKER(CHECKERNAME) \
501  void ento::register##CHECKERNAME(CheckerManager &mgr) { \
502  mgr.registerChecker<CHECKERNAME>(); \
503  } \
504  \
505  bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) { \
506  return true; \
507  }
508 
509 REGISTER_CHECKER(UnixAPIMisuseChecker)
510 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:1389
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:737
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:56
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:500
V
#define V(N, I)
Definition: ASTContext.h:3208
IsZeroByteAllocation
static bool IsZeroByteAllocation(ProgramStateRef state, const SVal argVal, ProgramStateRef *trueState, ProgramStateRef *falseState)
Definition: UnixAPIChecker.cpp:322
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:1847
CheckerManager.h
clang::CallExpr::getArg
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3002
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:2989
State
LineState State
Definition: UnwrappedLineFormatter.cpp:1147
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:7212
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:1904
clang::CallExpr
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2811
clang::ento::ObjKind::OS
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...