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"
26 using namespace clang;
41 class UnixAPIMisuseChecker :
public Checker< check::PreStmt<CallExpr> > {
42 mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
46 void checkPreStmt(
const CallExpr *CE, CheckerContext &C)
const;
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;
52 void CheckOpenVariant(CheckerContext &C,
55 void ReportOpenBug(CheckerContext &C,
62 class UnixAPIPortabilityChecker :
public Checker< check::PreStmt<CallExpr> > {
64 void checkPreStmt(
const CallExpr *CE, CheckerContext &C)
const;
67 mutable std::unique_ptr<BugType> BT_mallocZero;
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;
77 bool ReportZeroByteAllocation(CheckerContext &C,
80 const char *fn_name)
const;
81 void BasicAllocationCheck(CheckerContext &C,
83 const unsigned numArgs,
84 const unsigned sizeArg,
85 const char *fn)
const;
91 std::unique_ptr<BugType> &BT,
102 void UnixAPIMisuseChecker::checkPreStmt(
const CallExpr *CE,
103 CheckerContext &C)
const {
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);
127 void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
131 ExplodedNode *N =
C.generateErrorNode(
State);
137 auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
138 Report->addRange(SR);
139 C.emitReport(std::move(Report));
142 void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
147 void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
152 void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
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)) {
235 NonLoc oflags =
V.castAs<NonLoc>();
236 NonLoc ocreateFlag =
C.getSValBuilder()
237 .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->
getType()).castAs<NonLoc>();
238 SVal maskedFlagsUC =
C.getSValBuilder().evalBinOpNN(
state, BO_And,
241 if (maskedFlagsUC.isUnknownOrUndef())
243 DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
247 std::tie(trueState, falseState) =
state->assume(maskedFlags);
251 if (!(trueState && !falseState))
256 llvm::raw_svector_ostream
OS(SBuf);
257 OS <<
"Call to '" << VariantName <<
"' requires a "
258 << CreateModeArgIndex + 1
259 << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
260 <<
" argument when the 'O_CREAT' flag is set";
261 ReportOpenBug(C, trueState,
271 void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
283 const MemRegion *R =
C.getSVal(CE->
getArg(0)).getAsRegion();
284 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
287 ExplodedNode *N =
C.generateErrorNode(
state);
292 llvm::raw_svector_ostream os(S);
293 os <<
"Call to 'pthread_once' uses";
294 if (
const VarRegion *VR = dyn_cast<VarRegion>(R))
295 os <<
" the local variable '" << VR->getDecl()->getName() <<
'\'';
297 os <<
" stack allocated memory";
298 os <<
" for the \"control\" value. Using such transient memory for "
299 "the control value is potentially dangerous.";
300 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
301 os <<
" Perhaps you intended to declare the variable as 'static'?";
303 LazyInitialize(
this, BT_pthreadOnce,
"Improper use of 'pthread_once'");
306 std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N);
308 C.emitReport(std::move(report));
325 std::tie(*trueState, *falseState) =
326 state->assume(argVal.castAs<DefinedSVal>());
328 return (*falseState && !*trueState);
334 bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
338 const char *fn_name)
const {
339 ExplodedNode *N =
C.generateErrorNode(falseState);
344 "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
347 llvm::raw_svector_ostream os(S);
348 os <<
"Call to '" << fn_name <<
"' has an allocation size of 0 bytes";
350 std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
352 report->addRange(
arg->getSourceRange());
354 C.emitReport(std::move(report));
361 void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
363 const unsigned numArgs,
364 const unsigned sizeArg,
365 const char *fn)
const {
374 SVal argVal =
C.getSVal(
arg);
376 if (argVal.isUnknownOrUndef())
381 (void) ReportZeroByteAllocation(C, falseState,
arg, fn);
386 if (trueState !=
state)
387 C.addTransition(trueState);
390 void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
400 for (i = 0; i < nArgs; i++) {
402 SVal argVal =
C.getSVal(
arg);
403 if (argVal.isUnknownOrUndef()) {
411 if (ReportZeroByteAllocation(C, falseState,
arg,
"calloc"))
422 if (trueState !=
state)
423 C.addTransition(trueState);
426 void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
428 BasicAllocationCheck(C, CE, 1, 0,
"malloc");
431 void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
433 BasicAllocationCheck(C, CE, 2, 1,
"realloc");
436 void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
438 BasicAllocationCheck(C, CE, 2, 1,
"reallocf");
441 void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
443 BasicAllocationCheck(C, CE, 1, 0,
"alloca");
446 void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
449 BasicAllocationCheck(C, CE, 2, 0,
"__builtin_alloca_with_align");
452 void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
454 BasicAllocationCheck(C, CE, 1, 0,
"valloc");
457 void UnixAPIPortabilityChecker::checkPreStmt(
const CallExpr *CE,
458 CheckerContext &C)
const {
460 if (!FD || FD->
getKind() != Decl::Function)
466 if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx))
469 StringRef FName =
C.getCalleeName(FD);
473 if (FName ==
"calloc")
474 CheckCallocZero(C, CE);
476 else if (FName ==
"malloc")
477 CheckMallocZero(C, CE);
479 else if (FName ==
"realloc")
480 CheckReallocZero(C, CE);
482 else if (FName ==
"reallocf")
483 CheckReallocfZero(C, CE);
485 else if (FName ==
"alloca" || FName ==
"__builtin_alloca")
486 CheckAllocaZero(C, CE);
488 else if (FName ==
"__builtin_alloca_with_align")
489 CheckAllocaWithAlignZero(C, CE);
491 else if (FName ==
"valloc")
492 CheckVallocZero(C, CE);
499 #define REGISTER_CHECKER(CHECKERNAME) \
500 void ento::register##CHECKERNAME(CheckerManager &mgr) { \
501 mgr.registerChecker<CHECKERNAME>(); \
504 bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) { \