21 #include "llvm/ADT/Optional.h" 22 #include "llvm/ADT/STLExtras.h" 23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/ADT/StringExtras.h" 25 #include "llvm/ADT/StringSwitch.h" 26 #include "llvm/Support/raw_ostream.h" 29 using namespace clang;
43 class UnixAPIChecker :
public Checker< check::PreStmt<CallExpr> > {
44 mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;
68 void CheckOpenVariant(CheckerContext &C,
71 bool ReportZeroByteAllocation(CheckerContext &C,
74 const char *fn_name)
const;
75 void BasicAllocationCheck(CheckerContext &C,
77 const unsigned numArgs,
78 const unsigned sizeArg,
79 const char *fn)
const;
80 void LazyInitialize(std::unique_ptr<BugType> &BT,
const char *name)
const {
85 void ReportOpenBug(CheckerContext &C,
104 LazyInitialize(BT_open,
"Improper use of 'open'");
106 auto Report = llvm::make_unique<BugReport>(*BT_open, Msg, N);
107 Report->addRange(SR);
124 unsigned int FlagsArgIndex;
125 const char *VariantName;
129 VariantName =
"open";
133 VariantName =
"openat";
138 unsigned int MinArgCount = FlagsArgIndex + 1;
142 unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
145 unsigned int MaxArgCount = CreateModeArgIndex + 1;
154 const Expr *Arg = CE->
getArg(CreateModeArgIndex);
158 llvm::raw_svector_ostream OS(SBuf);
159 OS <<
"The " << CreateModeArgIndex + 1
160 << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
161 <<
" argument to '" << VariantName <<
"' is not an integer";
163 ReportOpenBug(C, state,
170 llvm::raw_svector_ostream OS(SBuf);
171 OS <<
"Call to '" << VariantName <<
"' with more than " << MaxArgCount
174 ReportOpenBug(C, state,
182 if (!Val_O_CREAT.hasValue()) {
184 == llvm::Triple::Apple)
185 Val_O_CREAT = 0x0200;
196 const Expr *oflagsEx = CE->
getArg(FlagsArgIndex);
215 std::tie(trueState, falseState) = state->assume(maskedFlags);
219 if (!(trueState && !falseState))
224 llvm::raw_svector_ostream OS(SBuf);
225 OS <<
"Call to '" << VariantName <<
"' requires a " 226 << CreateModeArgIndex + 1
227 << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
228 <<
" argument when the 'O_CREAT' flag is set";
229 ReportOpenBug(C, trueState,
260 llvm::raw_svector_ostream os(S);
261 os <<
"Call to 'pthread_once' uses";
262 if (
const VarRegion *VR = dyn_cast<VarRegion>(R))
263 os <<
" the local variable '" << VR->getDecl()->getName() <<
'\'';
265 os <<
" stack allocated memory";
266 os <<
" for the \"control\" value. Using such transient memory for " 267 "the control value is potentially dangerous.";
268 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->
getMemorySpace()))
269 os <<
" Perhaps you intended to declare the variable as 'static'?";
271 LazyInitialize(BT_pthreadOnce,
"Improper use of 'pthread_once'");
273 auto report = llvm::make_unique<BugReport>(*BT_pthreadOnce, os.str(), N);
291 std::tie(*trueState, *falseState) =
294 return (*falseState && !*trueState);
303 const char *fn_name)
const {
308 LazyInitialize(BT_mallocZero,
309 "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
312 llvm::raw_svector_ostream os(S);
313 os <<
"Call to '" << fn_name <<
"' has an allocation size of 0 bytes";
314 auto report = llvm::make_unique<BugReport>(*BT_mallocZero, os.str(), N);
317 bugreporter::trackNullOrUndefValue(N, arg, *report);
327 const unsigned numArgs,
328 const unsigned sizeArg,
329 const char *fn)
const {
345 (void) ReportZeroByteAllocation(C, falseState, arg, fn);
350 if (trueState != state)
364 for (i = 0; i < nArgs; i++) {
375 if (ReportZeroByteAllocation(C, falseState, arg,
"calloc"))
386 if (trueState != state)
392 BasicAllocationCheck(C, CE, 1, 0,
"malloc");
397 BasicAllocationCheck(C, CE, 2, 1,
"realloc");
402 BasicAllocationCheck(C, CE, 2, 1,
"reallocf");
407 BasicAllocationCheck(C, CE, 1, 0,
"alloca");
412 BasicAllocationCheck(C, CE, 2, 0,
"__builtin_alloca_with_align");
417 BasicAllocationCheck(C, CE, 1, 0,
"valloc");
425 void UnixAPIChecker::checkPreStmt(
const CallExpr *CE,
434 if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
443 llvm::StringSwitch<SubChecker>(FName)
444 .Case(
"open", &UnixAPIChecker::CheckOpen)
445 .Case(
"openat", &UnixAPIChecker::CheckOpenAt)
446 .Case(
"pthread_once", &UnixAPIChecker::CheckPthreadOnce)
451 if (CheckPortability) {
453 llvm::StringSwitch<SubChecker>(FName)
454 .Case(
"calloc", &UnixAPIChecker::CheckCallocZero)
455 .Case(
"malloc", &UnixAPIChecker::CheckMallocZero)
456 .Case(
"realloc", &UnixAPIChecker::CheckReallocZero)
457 .Case(
"reallocf", &UnixAPIChecker::CheckReallocfZero)
458 .Cases(
"alloca",
"__builtin_alloca",
459 &UnixAPIChecker::CheckAllocaZero)
460 .Case(
"__builtin_alloca_with_align",
461 &UnixAPIChecker::CheckAllocaWithAlignZero)
462 .Case(
"valloc", &UnixAPIChecker::CheckVallocZero)
473 #define REGISTER_CHECKER(Name) \ 474 void ento::registerUnixAPI##Name##Checker(CheckerManager &mgr) { \ 475 mgr.registerChecker<UnixAPIChecker>()->Check##Name = true; \
Represents a function declaration or definition.
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
A helper class which wraps a boolean value set to false by default.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
const TargetInfo & getTargetInfo() const
constexpr XRayInstrMask Function
const FunctionDecl * getCalleeDecl(const CallExpr *CE) const
Get the declaration of the called function (path-sensitive).
const char *const UnixAPI
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
StringRef getCalleeName(const FunctionDecl *FunDecl) const
Get the name of the called function (path-sensitive).
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.
const MemSpaceRegion * getMemorySpace() const
Expr - This represents one expression.
static bool IsZeroByteAllocation(ProgramStateRef state, const SVal argVal, ProgramStateRef *trueState, ProgramStateRef *falseState)
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
Dataflow Directional Tag Classes.
ASTContext & getASTContext()
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
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...
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const ProgramStateRef & getState() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SValBuilder & getSValBuilder()
Defines the clang::TargetInfo interface.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
#define REGISTER_CHECKER(Name)
A trivial tuple used to represent a source range.
bool isUnknownOrUndef() const