20 #include "llvm/ADT/Optional.h" 21 #include "llvm/ADT/STLExtras.h" 22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/Support/raw_ostream.h" 25 using namespace clang;
40 class UnixAPIMisuseChecker :
public Checker< check::PreStmt<CallExpr> > {
41 mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
45 DefaultBool CheckMisuse, CheckPortability;
47 void checkPreStmt(
const CallExpr *CE, CheckerContext &C)
const;
49 void CheckOpen(CheckerContext &C,
const CallExpr *CE)
const;
50 void CheckOpenAt(CheckerContext &C,
const CallExpr *CE)
const;
51 void CheckPthreadOnce(CheckerContext &C,
const CallExpr *CE)
const;
53 void CheckOpenVariant(CheckerContext &C,
56 void ReportOpenBug(CheckerContext &C,
63 class UnixAPIPortabilityChecker :
public Checker< check::PreStmt<CallExpr> > {
65 void checkPreStmt(
const CallExpr *CE, CheckerContext &C)
const;
68 mutable std::unique_ptr<BugType> BT_mallocZero;
70 void CheckCallocZero(CheckerContext &C,
const CallExpr *CE)
const;
71 void CheckMallocZero(CheckerContext &C,
const CallExpr *CE)
const;
72 void CheckReallocZero(CheckerContext &C,
const CallExpr *CE)
const;
73 void CheckReallocfZero(CheckerContext &C,
const CallExpr *CE)
const;
74 void CheckAllocaZero(CheckerContext &C,
const CallExpr *CE)
const;
75 void CheckAllocaWithAlignZero(CheckerContext &C,
const CallExpr *CE)
const;
76 void CheckVallocZero(CheckerContext &C,
const CallExpr *CE)
const;
78 bool ReportZeroByteAllocation(CheckerContext &C,
81 const char *fn_name)
const;
82 void BasicAllocationCheck(CheckerContext &C,
84 const unsigned numArgs,
85 const unsigned sizeArg,
86 const char *fn)
const;
92 std::unique_ptr<BugType> &BT,
103 void UnixAPIMisuseChecker::checkPreStmt(
const CallExpr *CE,
104 CheckerContext &C)
const {
112 if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
115 StringRef FName = C.getCalleeName(FD);
122 else if (FName ==
"openat")
125 else if (FName ==
"pthread_once")
126 CheckPthreadOnce(C, CE);
128 void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
132 ExplodedNode *N = C.generateErrorNode(
State);
138 auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
139 Report->addRange(SR);
140 C.emitReport(std::move(Report));
143 void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
148 void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
153 void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
158 unsigned int FlagsArgIndex;
159 const char *VariantName;
163 VariantName =
"open";
167 VariantName =
"openat";
172 unsigned int MinArgCount = FlagsArgIndex + 1;
176 unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
179 unsigned int MaxArgCount = CreateModeArgIndex + 1;
188 const Expr *Arg = CE->
getArg(CreateModeArgIndex);
192 llvm::raw_svector_ostream
OS(SBuf);
193 OS <<
"The " << CreateModeArgIndex + 1
194 << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
195 <<
" argument to '" << VariantName <<
"' is not an integer";
197 ReportOpenBug(C, state,
204 llvm::raw_svector_ostream
OS(SBuf);
205 OS <<
"Call to '" << VariantName <<
"' with more than " << MaxArgCount
208 ReportOpenBug(C, state,
216 if (!Val_O_CREAT.hasValue()) {
217 if (C.getASTContext().getTargetInfo().getTriple().getVendor()
218 == llvm::Triple::Apple)
219 Val_O_CREAT = 0x0200;
230 const Expr *oflagsEx = CE->
getArg(FlagsArgIndex);
231 const SVal
V = C.getSVal(oflagsEx);
232 if (!V.getAs<NonLoc>()) {
237 NonLoc oflags = V.castAs<NonLoc>();
238 NonLoc ocreateFlag = C.getSValBuilder()
239 .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->
getType()).castAs<NonLoc>();
240 SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
243 if (maskedFlagsUC.isUnknownOrUndef())
245 DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
249 std::tie(trueState, falseState) = state->assume(maskedFlags);
253 if (!(trueState && !falseState))
258 llvm::raw_svector_ostream
OS(SBuf);
259 OS <<
"Call to '" << VariantName <<
"' requires a " 260 << CreateModeArgIndex + 1
261 << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
262 <<
" argument when the 'O_CREAT' flag is set";
263 ReportOpenBug(C, trueState,
273 void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
285 const MemRegion *R = C.getSVal(CE->
getArg(0)).getAsRegion();
286 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
289 ExplodedNode *N = C.generateErrorNode(state);
294 llvm::raw_svector_ostream os(S);
295 os <<
"Call to 'pthread_once' uses";
296 if (
const VarRegion *VR = dyn_cast<VarRegion>(R))
297 os <<
" the local variable '" << VR->getDecl()->getName() <<
'\'';
299 os <<
" stack allocated memory";
300 os <<
" for the \"control\" value. Using such transient memory for " 301 "the control value is potentially dangerous.";
302 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
303 os <<
" Perhaps you intended to declare the variable as 'static'?";
305 LazyInitialize(
this, BT_pthreadOnce,
"Improper use of 'pthread_once'");
308 std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N);
310 C.emitReport(std::move(report));
327 std::tie(*trueState, *falseState) =
328 state->assume(argVal.castAs<DefinedSVal>());
330 return (*falseState && !*trueState);
336 bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
340 const char *fn_name)
const {
341 ExplodedNode *N = C.generateErrorNode(falseState);
346 "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
349 llvm::raw_svector_ostream os(S);
350 os <<
"Call to '" << fn_name <<
"' has an allocation size of 0 bytes";
352 std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
355 bugreporter::trackExpressionValue(N, arg, *report);
356 C.emitReport(std::move(report));
363 void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
365 const unsigned numArgs,
366 const unsigned sizeArg,
367 const char *fn)
const {
376 SVal argVal = C.getSVal(arg);
378 if (argVal.isUnknownOrUndef())
383 (void) ReportZeroByteAllocation(C, falseState, arg, fn);
388 if (trueState != state)
389 C.addTransition(trueState);
392 void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
402 for (i = 0; i < nArgs; i++) {
404 SVal argVal = C.getSVal(arg);
405 if (argVal.isUnknownOrUndef()) {
413 if (ReportZeroByteAllocation(C, falseState, arg,
"calloc"))
424 if (trueState != state)
425 C.addTransition(trueState);
428 void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
430 BasicAllocationCheck(C, CE, 1, 0,
"malloc");
433 void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
435 BasicAllocationCheck(C, CE, 2, 1,
"realloc");
438 void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
440 BasicAllocationCheck(C, CE, 2, 1,
"reallocf");
443 void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
445 BasicAllocationCheck(C, CE, 1, 0,
"alloca");
448 void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
451 BasicAllocationCheck(C, CE, 2, 0,
"__builtin_alloca_with_align");
454 void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
456 BasicAllocationCheck(C, CE, 1, 0,
"valloc");
459 void UnixAPIPortabilityChecker::checkPreStmt(
const CallExpr *CE,
460 CheckerContext &C)
const {
468 if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
471 StringRef FName = C.getCalleeName(FD);
475 if (FName ==
"calloc")
476 CheckCallocZero(C, CE);
478 else if (FName ==
"malloc")
479 CheckMallocZero(C, CE);
481 else if (FName ==
"realloc")
482 CheckReallocZero(C, CE);
484 else if (FName ==
"reallocf")
485 CheckReallocfZero(C, CE);
487 else if (FName ==
"alloca" || FName ==
"__builtin_alloca")
488 CheckAllocaZero(C, CE);
490 else if (FName ==
"__builtin_alloca_with_align")
491 CheckAllocaWithAlignZero(C, CE);
493 else if (FName ==
"valloc")
494 CheckVallocZero(C, CE);
501 #define REGISTER_CHECKER(CHECKERNAME) \ 502 void ento::register##CHECKERNAME(CheckerManager &mgr) { \ 503 mgr.registerChecker<CHECKERNAME>(); \ 506 bool ento::shouldRegister##CHECKERNAME(const LangOptions &LO) { \
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.
static void LazyInitialize(const CheckerBase *Checker, std::unique_ptr< BugType > &BT, const char *name)
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(CHECKERNAME)
A trivial tuple used to represent a source range.