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;
48 DefaultBool CheckMisuse, CheckPortability;
50 void checkPreStmt(
const CallExpr *CE, CheckerContext &C)
const;
52 void CheckOpen(CheckerContext &C,
const CallExpr *CE)
const;
53 void CheckOpenAt(CheckerContext &C,
const CallExpr *CE)
const;
55 void CheckPthreadOnce(CheckerContext &C,
const CallExpr *CE)
const;
56 void CheckCallocZero(CheckerContext &C,
const CallExpr *CE)
const;
57 void CheckMallocZero(CheckerContext &C,
const CallExpr *CE)
const;
58 void CheckReallocZero(CheckerContext &C,
const CallExpr *CE)
const;
59 void CheckReallocfZero(CheckerContext &C,
const CallExpr *CE)
const;
60 void CheckAllocaZero(CheckerContext &C,
const CallExpr *CE)
const;
61 void CheckAllocaWithAlignZero(CheckerContext &C,
const CallExpr *CE)
const;
62 void CheckVallocZero(CheckerContext &C,
const CallExpr *CE)
const;
64 typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,
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,
96 void UnixAPIChecker::ReportOpenBug(CheckerContext &C,
100 ExplodedNode *N = C.generateErrorNode(
State);
104 LazyInitialize(BT_open,
"Improper use of 'open'");
106 auto Report = llvm::make_unique<BugReport>(*BT_open, Msg, N);
107 Report->addRange(SR);
108 C.emitReport(std::move(Report));
111 void UnixAPIChecker::CheckOpen(CheckerContext &C,
const CallExpr *CE)
const {
115 void UnixAPIChecker::CheckOpenAt(CheckerContext &C,
const CallExpr *CE)
const {
119 void UnixAPIChecker::CheckOpenVariant(CheckerContext &C,
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()) {
183 if (C.getASTContext().getTargetInfo().getTriple().getVendor()
184 == llvm::Triple::Apple)
185 Val_O_CREAT = 0x0200;
196 const Expr *oflagsEx = CE->
getArg(FlagsArgIndex);
197 const SVal V = C.getSVal(oflagsEx);
198 if (!V.getAs<NonLoc>()) {
203 NonLoc oflags = V.castAs<NonLoc>();
204 NonLoc ocreateFlag = C.getSValBuilder()
205 .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->
getType()).castAs<NonLoc>();
206 SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
209 if (maskedFlagsUC.isUnknownOrUndef())
211 DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
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,
239 void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
251 const MemRegion *R = C.getSVal(CE->
getArg(0)).getAsRegion();
252 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
255 ExplodedNode *N = C.generateErrorNode(state);
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);
275 C.emitReport(std::move(report));
291 std::tie(*trueState, *falseState) =
292 state->assume(argVal.castAs<DefinedSVal>());
294 return (*falseState && !*trueState);
300 bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
303 const char *fn_name)
const {
304 ExplodedNode *N = C.generateErrorNode(falseState);
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::trackExpressionValue(N, arg, *report);
318 C.emitReport(std::move(report));
325 void UnixAPIChecker::BasicAllocationCheck(CheckerContext &C,
327 const unsigned numArgs,
328 const unsigned sizeArg,
329 const char *fn)
const {
338 SVal argVal = C.getSVal(arg);
340 if (argVal.isUnknownOrUndef())
345 (void) ReportZeroByteAllocation(C, falseState, arg, fn);
350 if (trueState != state)
351 C.addTransition(trueState);
354 void UnixAPIChecker::CheckCallocZero(CheckerContext &C,
364 for (i = 0; i < nArgs; i++) {
366 SVal argVal = C.getSVal(arg);
367 if (argVal.isUnknownOrUndef()) {
375 if (ReportZeroByteAllocation(C, falseState, arg,
"calloc"))
386 if (trueState != state)
387 C.addTransition(trueState);
390 void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
392 BasicAllocationCheck(C, CE, 1, 0,
"malloc");
395 void UnixAPIChecker::CheckReallocZero(CheckerContext &C,
397 BasicAllocationCheck(C, CE, 2, 1,
"realloc");
400 void UnixAPIChecker::CheckReallocfZero(CheckerContext &C,
402 BasicAllocationCheck(C, CE, 2, 1,
"reallocf");
405 void UnixAPIChecker::CheckAllocaZero(CheckerContext &C,
407 BasicAllocationCheck(C, CE, 1, 0,
"alloca");
410 void UnixAPIChecker::CheckAllocaWithAlignZero(CheckerContext &C,
412 BasicAllocationCheck(C, CE, 2, 0,
"__builtin_alloca_with_align");
415 void UnixAPIChecker::CheckVallocZero(CheckerContext &C,
417 BasicAllocationCheck(C, CE, 1, 0,
"valloc");
425 void UnixAPIChecker::checkPreStmt(
const CallExpr *CE,
426 CheckerContext &C)
const {
434 if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
437 StringRef FName = C.getCalleeName(FD);
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.
A (possibly-)qualified type.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
constexpr XRayInstrMask Function
const char *const UnixAPI
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.
This represents one expression.
static bool IsZeroByteAllocation(ProgramStateRef state, const SVal argVal, ProgramStateRef *trueState, ProgramStateRef *falseState)
Dataflow Directional Tag Classes.
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...
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
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.