20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/SmallString.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/Support/raw_ostream.h"
41class UnixAPIMisuseChecker :
public Checker< check::PreStmt<CallExpr> > {
42 mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
43 mutable std::optional<uint64_t> Val_O_CREAT;
62class UnixAPIPortabilityChecker :
public Checker< check::PreStmt<CallExpr> > {
67 mutable std::unique_ptr<BugType> BT_mallocZero;
80 const char *fn_name)
const;
83 const unsigned numArgs,
84 const unsigned sizeArg,
85 const char *fn)
const;
91 std::unique_ptr<BugType> &BT,
102void UnixAPIMisuseChecker::checkPreStmt(
const CallExpr *CE,
105 if (!FD || FD->
getKind() != Decl::Function)
111 if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx))
114 StringRef FName =
C.getCalleeName(FD);
121 else if (FName ==
"openat")
124 else if (FName ==
"pthread_once")
125 CheckPthreadOnce(
C, CE);
137 auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
138 Report->addRange(SR);
139 C.emitReport(std::move(Report));
157 unsigned int FlagsArgIndex;
158 const char *VariantName;
162 VariantName =
"open";
166 VariantName =
"openat";
171 unsigned int MinArgCount = FlagsArgIndex + 1;
175 unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
178 unsigned int MaxArgCount = CreateModeArgIndex + 1;
186 const Expr *Arg = CE->
getArg(CreateModeArgIndex);
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";
195 ReportOpenBug(
C, state,
202 llvm::raw_svector_ostream OS(SBuf);
203 OS <<
"Call to '" << VariantName <<
"' with more than " << MaxArgCount
206 ReportOpenBug(
C, state,
215 if (
C.getASTContext().getTargetInfo().getTriple().getVendor()
216 == llvm::Triple::Apple)
217 Val_O_CREAT = 0x0200;
228 const Expr *oflagsEx = CE->
getArg(FlagsArgIndex);
229 const SVal V =
C.getSVal(oflagsEx);
230 if (!isa<NonLoc>(
V)) {
236 NonLoc ocreateFlag =
C.getSValBuilder()
237 .makeIntVal(*Val_O_CREAT, oflagsEx->
getType())
239 SVal maskedFlagsUC =
C.getSValBuilder().evalBinOpNN(state, BO_And,
248 std::tie(trueState, falseState) = state->assume(maskedFlags);
252 if (!(trueState && !falseState))
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,
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() <<
'\'';
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'?";
304 LazyInitialize(
this, BT_pthreadOnce,
"Improper use of 'pthread_once'");
307 std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N);
309 C.emitReport(std::move(report));
326 std::tie(*trueState, *falseState) =
329 return (*falseState && !*trueState);
335bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
339 const char *fn_name)
const {
345 "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
348 llvm::raw_svector_ostream os(S);
349 os <<
"Call to '" << fn_name <<
"' has an allocation size of 0 bytes";
351 std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
353 report->addRange(
arg->getSourceRange());
355 C.emitReport(std::move(report));
364 const unsigned numArgs,
365 const unsigned sizeArg,
366 const char *fn)
const {
375 SVal argVal =
C.getSVal(arg);
382 (void) ReportZeroByteAllocation(
C, falseState, arg, fn);
387 if (trueState != state)
388 C.addTransition(trueState);
401 for (i = 0; i < nArgs; i++) {
403 SVal argVal =
C.getSVal(arg);
412 if (ReportZeroByteAllocation(
C, falseState, arg,
"calloc"))
423 if (trueState != state)
424 C.addTransition(trueState);
429 BasicAllocationCheck(
C, CE, 1, 0,
"malloc");
434 BasicAllocationCheck(
C, CE, 2, 1,
"realloc");
439 BasicAllocationCheck(
C, CE, 2, 1,
"reallocf");
444 BasicAllocationCheck(
C, CE, 1, 0,
"alloca");
447void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
450 BasicAllocationCheck(
C, CE, 2, 0,
"__builtin_alloca_with_align");
455 BasicAllocationCheck(
C, CE, 1, 0,
"valloc");
458void UnixAPIPortabilityChecker::checkPreStmt(
const CallExpr *CE,
461 if (!FD || FD->
getKind() != Decl::Function)
467 if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx))
470 StringRef FName =
C.getCalleeName(FD);
474 if (FName ==
"calloc")
475 CheckCallocZero(
C, CE);
477 else if (FName ==
"malloc")
478 CheckMallocZero(
C, CE);
480 else if (FName ==
"realloc")
481 CheckReallocZero(
C, CE);
483 else if (FName ==
"reallocf")
484 CheckReallocfZero(
C, CE);
486 else if (FName ==
"alloca" || FName ==
"__builtin_alloca")
487 CheckAllocaZero(
C, CE);
489 else if (FName ==
"__builtin_alloca_with_align")
490 CheckAllocaWithAlignZero(
C, CE);
492 else if (FName ==
"valloc")
493 CheckVallocZero(
C, CE);
500#define REGISTER_CHECKER(CHECKERNAME) \
501 void ento::register##CHECKERNAME(CheckerManager &mgr) { \
502 mgr.registerChecker<CHECKERNAME>(); \
505 bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) { \
static bool IsZeroByteAllocation(ProgramStateRef state, const SVal argVal, ProgramStateRef *trueState, ProgramStateRef *falseState)
static void LazyInitialize(const CheckerBase *Checker, std::unique_ptr< BugType > &BT, const char *name)
@ OpenAt
The variant taking a directory file descriptor and a relative path: int openat(int fd,...
@ Open
The standard open() call: int open(const char *path, int oflag, ...);.
#define REGISTER_CHECKER(CHECKERNAME)
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
DeclContext * getEnclosingNamespaceContext()
Retrieve the nearest enclosing namespace context.
This represents one expression.
Represents a function declaration or definition.
A (possibly-)qualified type.
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isUnknownOrUndef() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Defines the clang::TargetInfo interface.
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.
const char *const UnixAPI
__DEVICE__ _Tp arg(const std::complex< _Tp > &__c)