84#include "llvm/ADT/STLExtras.h"
85#include "llvm/ADT/SmallVector.h"
86#include "llvm/ADT/StringExtras.h"
87#include "llvm/Support/Casting.h"
88#include "llvm/Support/Compiler.h"
89#include "llvm/Support/ErrorHandling.h"
90#include "llvm/Support/raw_ostream.h"
97using namespace std::placeholders;
109enum AllocationFamilyKind {
120struct AllocationFamily {
121 AllocationFamilyKind Kind;
122 std::optional<StringRef> CustomName;
124 explicit AllocationFamily(AllocationFamilyKind AKind,
125 std::optional<StringRef> Name = std::nullopt)
126 : Kind(AKind), CustomName(Name) {
127 assert((Kind != AF_Custom || CustomName.has_value()) &&
128 "Custom family must specify also the name");
131 if (Kind == AF_Custom && CustomName.value() ==
"malloc") {
133 CustomName = std::nullopt;
138 return std::tie(Kind, CustomName) == std::tie(
Other.Kind,
Other.CustomName);
142 return !(*
this ==
Other);
145 void Profile(llvm::FoldingSetNodeID &ID)
const {
148 if (Kind == AF_Custom)
149 ID.AddString(CustomName.value());
194 AllocationFamily Family;
196 RefState(Kind k,
const Stmt *s, AllocationFamily family)
197 : S(s), K(k), Family(family) {
198 assert(family.Kind != AF_None);
202 bool isAllocated()
const {
return K == Allocated; }
203 bool isAllocatedOfSizeZero()
const {
return K == AllocatedOfSizeZero; }
204 bool isReleased()
const {
return K == Released; }
205 bool isRelinquished()
const {
return K == Relinquished; }
206 bool isEscaped()
const {
return K == Escaped; }
207 AllocationFamily getAllocationFamily()
const {
return Family; }
208 const Stmt *getStmt()
const {
return S; }
211 return K ==
X.K && S ==
X.S && Family ==
X.Family;
214 static RefState getAllocated(AllocationFamily family,
const Stmt *s) {
215 return RefState(Allocated, s, family);
217 static RefState getAllocatedOfSizeZero(
const RefState *RS) {
218 return RefState(AllocatedOfSizeZero, RS->getStmt(),
219 RS->getAllocationFamily());
221 static RefState getReleased(AllocationFamily family,
const Stmt *s) {
222 return RefState(Released, s, family);
224 static RefState getRelinquished(AllocationFamily family,
const Stmt *s) {
225 return RefState(Relinquished, s, family);
227 static RefState getEscaped(
const RefState *RS) {
228 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
231 void Profile(llvm::FoldingSetNodeID &ID)
const {
237 LLVM_DUMP_METHOD
void dump(raw_ostream &
OS)
const {
239#define CASE(ID) case ID: OS << #ID; break;
241 CASE(AllocatedOfSizeZero)
248 LLVM_DUMP_METHOD
void dump()
const {
dump(llvm::errs()); }
263 AllocationFamily Family,
264 std::optional<SVal> RetVal = std::nullopt);
278enum OwnershipAfterReallocKind {
280 OAR_ToBeFreedAfterFailure,
290 OAR_DoNotTrackAfterFailure
303 OwnershipAfterReallocKind Kind;
305 ReallocPair(
SymbolRef S, OwnershipAfterReallocKind K)
306 : ReallocatedSym(S), Kind(K) {}
307 void Profile(llvm::FoldingSetNodeID &ID)
const {
309 ID.AddPointer(ReallocatedSym);
312 return ReallocatedSym ==
X.ReallocatedSym &&
348#define BUGTYPE_PROVIDER(NAME, DEF) \
349 struct NAME : virtual public CheckerFrontend { \
350 BugType NAME##Bug{this, DEF, categories::MemoryError}; \
372#undef BUGTYPE_PROVIDER
374template <
typename... BT_PROVIDERS>
375struct DynMemFrontend :
virtual public CheckerFrontend,
public BT_PROVIDERS... {
376 template <
typename T>
const T *getAs()
const {
377 if constexpr (std::is_same_v<T, CheckerFrontend> ||
378 (std::is_same_v<T, BT_PROVIDERS> || ...))
379 return static_cast<const T *
>(
this);
390 check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape,
391 check::PreStmt<ReturnStmt>, check::EndFunction, check::PreCall,
392 check::PostCall, eval::Call, check::NewAllocator,
393 check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location,
400 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
402 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
410 bool ModelAllocationFailure =
false;
419 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
422 DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
424 DynMemFrontend<Leak> NewDeleteLeaksChecker;
425 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
426 DynMemFrontend<UseFree> InnerPointerChecker;
429 CheckerFrontendWithBugType TaintedAllocChecker{
"Tainted Memory Allocation",
432 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
434 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
435 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
436 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
439 handleSmartPointerConstructorArguments(
const CallEvent &
Call,
444 void checkNewAllocator(
const CXXAllocatorCall &
Call, CheckerContext &
C)
const;
445 void checkPostObjCMessage(
const ObjCMethodCall &
Call, CheckerContext &
C)
const;
446 void checkPostStmt(
const BlockExpr *BE, CheckerContext &
C)
const;
447 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &
C)
const;
448 void checkPreStmt(
const ReturnStmt *S, CheckerContext &
C)
const;
449 void checkEndFunction(
const ReturnStmt *S, CheckerContext &
C)
const;
451 bool Assumption)
const;
452 void checkLocation(SVal l,
bool isLoad,
const Stmt *S,
453 CheckerContext &
C)
const;
457 const CallEvent *
Call,
461 const CallEvent *
Call,
465 const char *NL,
const char *Sep)
const override;
467 StringRef getDebugTag()
const override {
return "MallocChecker"; }
470#define CHECK_FN(NAME) \
471 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
503 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},
504 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},
507 const CallDescriptionMap<CheckFn> PostFnMap{
510 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},
511 {{CDM::CLibrary, {
"getdelim"}, 4},
512 &MallocChecker::checkGetDelimOrGetLine},
515 const CallDescriptionMap<CheckFn> FreeingMemFnMap{
516 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
517 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
518 &MallocChecker::checkIfFreeNameIndex},
519 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
520 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
523 bool isFreeingCall(
const CallEvent &
Call)
const;
524 static bool isFreeingOwnershipAttrCall(
const FunctionDecl *
Func);
525 static bool isFreeingOwnershipAttrCall(
const CallEvent &
Call);
526 static bool isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func);
527 static bool isAllocatingOwnershipAttrCall(
const CallEvent &
Call);
529 friend class NoMemOwnershipChangeVisitor;
531 CallDescriptionMap<CheckFn> AllocaMemFnMap{
532 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
533 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
537 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
538 &MallocChecker::checkAlloca},
541 CallDescriptionMap<CheckFn> AllocatingMemFnMap{
542 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAllocMayFail},
543 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
544 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
545 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
546 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
547 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
548 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
549 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
550 {{CDM::CLibrary, {
"if_nameindex"}, 0}, &MallocChecker::checkIfNameIndex},
551 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
552 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
553 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
554 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
555 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
556 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
557 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
558 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
559 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
560 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
561 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
564 CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
565 {{CDM::CLibrary, {
"realloc"}, 2},
566 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
567 {{CDM::CLibrary, {
"reallocf"}, 2},
568 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
true)},
569 {{CDM::CLibrary, {
"g_realloc"}, 2},
570 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
571 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
572 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
573 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
574 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
577 bool isMemCall(
const CallEvent &
Call)
const;
578 bool hasOwnershipReturns(
const CallEvent &
Call)
const;
579 bool hasOwnershipTakesHolds(
const CallEvent &
Call)
const;
580 void reportTaintBug(StringRef Msg,
ProgramStateRef State, CheckerContext &
C,
581 llvm::ArrayRef<SymbolRef> TaintedSyms,
582 AllocationFamily Family)
const;
584 void checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
586 AllocationFamily Family)
const;
589 mutable std::optional<uint64_t> KernelZeroFlagVal;
591 using KernelZeroSizePtrValueTy = std::optional<int>;
596 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
601 processNewAllocation(
const CXXAllocatorCall &
Call, CheckerContext &
C,
602 AllocationFamily Family)
const;
613 ProcessZeroAllocCheck(CheckerContext &
C,
const CallEvent &
Call,
615 std::optional<SVal> RetVal = std::nullopt);
634 MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
644 const CallEvent &
Call,
646 bool isAlloca)
const;
658 MallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
const Expr *SizeEx,
671 const CallEvent &
Call, SVal Size,
673 AllocationFamily Family)
const;
686 llvm::ArrayRef<unsigned> SizeArgIndexes = {})
const;
690 [[nodiscard]] std::optional<ProgramStateRef>
691 performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
712 const CallEvent &
Call,
713 const OwnershipAttr *Att,
737 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
738 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
762 FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
const CallEvent &
Call,
764 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
765 std::optional<SVal> ArgValOpt = {})
const;
781 ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
bool ShouldFreeOnFail,
783 bool SuffixWithN =
false)
const;
790 [[nodiscard]]
static SVal evalMulForBufferSize(CheckerContext &
C,
792 const Expr *BlockBytes);
800 const CallEvent &
Call,
805 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
806 CheckerContext &
C)
const;
809 bool checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
const Stmt *S)
const;
813 void checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
814 const Stmt *S)
const;
826 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
835 bool IsConstPointerEscape)
const;
838 void checkEscapeOnReturn(
const ReturnStmt *S, CheckerContext &
C)
const;
847 const T *getRelevantFrontendAs(AllocationFamily Family)
const;
850 const T *getRelevantFrontendAs(CheckerContext &
C,
SymbolRef Sym)
const;
852 static bool SummarizeValue(raw_ostream &os, SVal
V);
854 const MemRegion *MR);
856 void HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal, SourceRange Range,
857 const Expr *DeallocExpr,
858 AllocationFamily Family)
const;
860 void HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
861 SourceRange Range)
const;
863 void HandleMismatchedDealloc(CheckerContext &
C, SourceRange Range,
864 const Expr *DeallocExpr,
const RefState *RS,
865 SymbolRef Sym,
bool OwnershipTransferred)
const;
867 void HandleOffsetFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
868 const Expr *DeallocExpr, AllocationFamily Family,
869 const Expr *AllocExpr =
nullptr)
const;
871 void HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
874 void HandleDoubleFree(CheckerContext &
C, SourceRange Range,
bool Released,
877 void HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
880 void HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
881 const Expr *FreeExpr,
882 AllocationFamily Family)
const;
886 static LeakInfo getAllocationSite(
const ExplodedNode *N,
SymbolRef Sym,
889 void HandleLeak(
SymbolRef Sym, ExplodedNode *N, CheckerContext &
C)
const;
902class NoMemOwnershipChangeVisitor final :
public NoOwnershipChangeVisitor {
911 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
912 const auto *MallocChk =
static_cast<const MallocChecker *
>(&Checker);
913 if (MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
914 MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
917 if (
const auto *
Func =
918 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
919 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
926 return CallEnterState->get<RegionState>(Sym) !=
927 CallExitEndState->get<RegionState>(Sym);
934 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
935 ASTContext &ACtx)
final {
936 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
951 using namespace clang::ast_matchers;
956 for (BoundNodes
Match : Matches) {
957 if (
Match.getNodeAs<CXXDeleteExpr>(
"delete"))
960 if (
const auto *
Call =
Match.getNodeAs<CallExpr>(
"call"))
961 if (isFreeingCallAsWritten(*
Call))
973 N->getState()->getStateManager().getContext().getSourceManager());
974 return std::make_shared<PathDiagnosticEventPiece>(
975 L,
"Returning without deallocating memory or storing the pointer for "
976 "later deallocation");
980 NoMemOwnershipChangeVisitor(
SymbolRef Sym,
const MallocChecker *Checker)
981 : NoOwnershipChangeVisitor(Sym, Checker) {}
983 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1002 enum NotificationMode { Normal, ReallocationFailed };
1008 NotificationMode Mode;
1015 const StackFrame *ReleaseFunctionSF;
1020 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
1021 : Sym(S), Mode(Normal), FailedReallocSymbol(
nullptr),
1022 ReleaseFunctionSF(
nullptr), IsLeak(isLeak) {}
1024 static void *getTag() {
1029 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1030 ID.AddPointer(getTag());
1035 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
1037 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
1039 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1041 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1046 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
1049 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
1050 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
1051 (!Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
1056 static inline bool isRelinquished(
const RefState *RSCurr,
1057 const RefState *RSPrev,
const Stmt *Stmt) {
1059 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
1060 (RSCurr && RSCurr->isRelinquished()) &&
1061 (!RSPrev || !RSPrev->isRelinquished()));
1068 static inline bool hasReallocFailed(
const RefState *RSCurr,
1069 const RefState *RSPrev,
1071 return ((!isa_and_nonnull<CallExpr>(Stmt)) &&
1073 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1075 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1079 BugReporterContext &BRC,
1080 PathSensitiveBugReport &BR)
override;
1083 BugReporterContext &BRC,
1084 PathSensitiveBugReport &BR)
override {
1090 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1095 class StackHintGeneratorForReallocationFailed
1096 :
public StackHintGeneratorForSymbol {
1098 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1099 : StackHintGeneratorForSymbol(S, M) {}
1101 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1105 SmallString<200> buf;
1106 llvm::raw_svector_ostream os(buf);
1108 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1109 <<
" parameter failed";
1111 return std::string(os.str());
1114 std::string getMessageForReturn(
const CallExpr *CallExpr)
override {
1115 return "Reallocation of returned value failed";
1133 bool VisitSymbol(
SymbolRef sym)
override {
1134 state = state->remove<RegionState>(sym);
1154 explicit EscapeTrackedCallback(
ProgramStateRef S) : State(std::move(S)) {}
1157 bool VisitSymbol(
SymbolRef Sym)
override {
1158 if (
const RefState *RS = State->get<RegionState>(Sym)) {
1159 if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) {
1160 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
1168 EscapeTrackedRegionsReachableFrom(ArrayRef<const MemRegion *> Roots,
1175 SmallVector<const MemRegion *, 10> Regions;
1176 EscapeTrackedCallback Visitor(State);
1177 for (
const MemRegion *R : Roots) {
1178 Regions.push_back(R);
1180 State->scanReachableSymbols(Regions, Visitor);
1181 return Visitor.State;
1184 friend class SymbolVisitor;
1193 if (Kind != OO_New && Kind != OO_Array_New)
1209 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1220 return L.
isInvalid() || (!HasBody && SM.isInSystemHeader(L));
1227bool MallocChecker::isFreeingOwnershipAttrCall(
const CallEvent &
Call) {
1228 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1230 return Func && isFreeingOwnershipAttrCall(
Func);
1233bool MallocChecker::isFreeingOwnershipAttrCall(
const FunctionDecl *
Func) {
1234 if (
Func->hasAttrs()) {
1235 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1236 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1237 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1244bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1248 return isFreeingOwnershipAttrCall(
Call);
1251bool MallocChecker::isAllocatingOwnershipAttrCall(
const CallEvent &
Call) {
1252 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1254 return Func && isAllocatingOwnershipAttrCall(
Func);
1257bool MallocChecker::isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func) {
1258 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1259 if (I->getOwnKind() == OwnershipAttr::Returns)
1266bool MallocChecker::isMemCall(
const CallEvent &
Call)
const {
1271 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1274 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1275 return Func &&
Func->hasAttr<OwnershipAttr>();
1278std::optional<ProgramStateRef>
1279MallocChecker::performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
1297 ASTContext &Ctx =
C.getASTContext();
1300 if (!KernelZeroFlagVal) {
1302 case llvm::Triple::FreeBSD:
1303 KernelZeroFlagVal = 0x0100;
1305 case llvm::Triple::NetBSD:
1306 KernelZeroFlagVal = 0x0002;
1308 case llvm::Triple::OpenBSD:
1309 KernelZeroFlagVal = 0x0008;
1311 case llvm::Triple::Linux:
1313 KernelZeroFlagVal = 0x8000;
1321 return std::nullopt;
1328 if (
Call.getNumArgs() < 2)
1329 return std::nullopt;
1331 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1332 const SVal
V =
C.getSVal(FlagsEx);
1336 return std::nullopt;
1339 NonLoc Flags =
V.castAs<NonLoc>();
1340 NonLoc ZeroFlag =
C.getSValBuilder()
1341 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1343 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1346 if (MaskedFlagsUC.isUnknownOrUndef())
1347 return std::nullopt;
1348 DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
1352 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1355 if (TrueState && !FalseState) {
1356 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1357 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1358 AllocationFamily(AF_Malloc));
1361 return std::nullopt;
1364SVal MallocChecker::evalMulForBufferSize(CheckerContext &
C,
const Expr *Blocks,
1365 const Expr *BlockBytes) {
1366 SValBuilder &SB =
C.getSValBuilder();
1367 SVal BlocksVal =
C.getSVal(Blocks);
1368 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1370 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1376 const CallEvent &
Call,
1377 CheckerContext &
C)
const {
1378 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1379 AllocationFamily(AF_Malloc));
1380 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1381 C.addTransition(State);
1385 const CallEvent &
Call,
1386 CheckerContext &
C)
const {
1387 C.addTransition(FailedAlloc(
C,
Call, State, {0}));
1389 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1390 AllocationFamily(AF_Malloc));
1391 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1392 C.addTransition(State);
1396 const CallEvent &
Call,
1397 CheckerContext &
C)
const {
1398 std::optional<ProgramStateRef> MaybeState =
1399 performKernelMalloc(
Call,
C, State);
1401 State = *MaybeState;
1403 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1404 AllocationFamily(AF_Malloc));
1405 C.addTransition(State);
1429 bool ShouldFreeOnFail)
const {
1439 if (StandardRealloc)
1440 C.addTransition(FailedAlloc(
C,
Call, State, {1}));
1442 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1443 AllocationFamily(AF_Malloc));
1444 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1445 C.addTransition(State);
1449 CheckerContext &
C)
const {
1450 C.addTransition(FailedAlloc(
C,
Call, State, {0, 1}));
1452 State = CallocMem(
C,
Call, State);
1453 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1454 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1455 C.addTransition(State);
1459 CheckerContext &
C)
const {
1460 bool IsKnownToBeAllocatedMemory =
false;
1461 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1463 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1464 AllocationFamily(AF_Malloc));
1465 C.addTransition(State);
1469 CheckerContext &
C)
const {
1470 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1471 AllocationFamily(AF_Alloca));
1472 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1473 C.addTransition(State);
1477 CheckerContext &
C)
const {
1478 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1482 C.addTransition(FailedAlloc(
C,
Call, State));
1484 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1485 AllocationFamily(AF_Malloc));
1486 C.addTransition(State);
1490 const CallEvent &
Call,
1491 CheckerContext &
C)
const {
1492 C.addTransition(FailedAlloc(
C,
Call, State));
1496 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1497 AllocationFamily(AF_IfNameIndex));
1498 C.addTransition(State);
1502 const CallEvent &
Call,
1503 CheckerContext &
C)
const {
1504 bool IsKnownToBeAllocatedMemory =
false;
1505 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1506 AllocationFamily(AF_IfNameIndex));
1507 C.addTransition(State);
1519 if (BuffType.isNull() || !BuffType->isVoidPointerType())
1525 const CallEvent &
Call,
1526 CheckerContext &
C)
const {
1527 bool IsKnownToBeAllocatedMemory =
false;
1528 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1538 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1541 auto RetVal = State->getSVal(BufArg,
Call.getStackFrame());
1542 State = State->BindExpr(CE,
C.getStackFrame(), RetVal);
1543 C.addTransition(State);
1549 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1550 AllocationFamily(AF_CXXNew));
1551 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1554 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1555 AllocationFamily(AF_CXXNewArray));
1556 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1559 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1560 AllocationFamily(AF_CXXNew));
1562 case OO_Array_Delete:
1563 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1564 AllocationFamily(AF_CXXNewArray));
1567 assert(
false &&
"not a new/delete operator");
1571 C.addTransition(State);
1575 CheckerContext &
C)
const {
1576 SValBuilder &svalBuilder =
C.getSValBuilder();
1578 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1579 AllocationFamily(AF_Malloc));
1580 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1581 C.addTransition(State);
1585 CheckerContext &
C)
const {
1586 State = MallocMemAux(
C,
Call,
Call.getArgExpr(1), UnknownVal(), State,
1587 AllocationFamily(AF_Malloc));
1588 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1589 C.addTransition(State);
1593 CheckerContext &
C)
const {
1594 SVal
Init = UndefinedVal();
1595 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1596 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1597 AllocationFamily(AF_Malloc));
1598 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1599 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1600 C.addTransition(State);
1604 CheckerContext &
C)
const {
1605 SValBuilder &SB =
C.getSValBuilder();
1607 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1608 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1609 AllocationFamily(AF_Malloc));
1610 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1611 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1612 C.addTransition(State);
1617 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1622 const CallEvent &
Call,
1623 CheckerContext &
C)
const {
1637 bool IsKnownToBeAllocated =
false;
1638 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1639 IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1642 C.addTransition(State);
1646 const CallEvent &
Call,
1647 CheckerContext &
C)
const {
1655 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1661 if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||
1662 SizeOpt->isUnknownOrUndef())
1665 const auto LinePtr = LinePtrOpt->getAs<DefinedSVal>();
1666 const auto Size = SizeOpt->getAs<DefinedSVal>();
1667 const MemRegion *LinePtrReg = LinePtr->getAsRegion();
1673 AllocationFamily(AF_Malloc), *LinePtr));
1677 CheckerContext &
C)
const {
1678 State = ReallocMemAux(
C,
Call,
false, State,
1679 AllocationFamily(AF_Malloc),
1681 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1682 State = ProcessZeroAllocCheck(
C,
Call, 2, State);
1683 C.addTransition(State);
1687 const CallEvent &
Call,
1688 CheckerContext &
C)
const {
1689 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1692 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1695 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1696 MismatchedDeallocatorChecker.isEnabled()) {
1701 switch (I->getOwnKind()) {
1702 case OwnershipAttr::Returns:
1703 State = MallocMemReturnsAttr(
C,
Call, I, State);
1705 case OwnershipAttr::Takes:
1706 case OwnershipAttr::Holds:
1707 State = FreeMemAttr(
C,
Call, I, State);
1712 C.addTransition(State);
1715bool MallocChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
1716 if (!
Call.getOriginExpr())
1722 (*Callback)(
this, State,
Call,
C);
1727 State = MallocBindRetVal(
C,
Call, State,
false);
1728 (*Callback)(
this, State,
Call,
C);
1733 State = MallocBindRetVal(
C,
Call, State,
false);
1734 (*Callback)(
this, State,
Call,
C);
1739 State = MallocBindRetVal(
C,
Call, State,
false);
1740 checkCXXNewOrCXXDelete(State,
Call,
C);
1745 checkCXXNewOrCXXDelete(State,
Call,
C);
1750 State = MallocBindRetVal(
C,
Call, State,
true);
1751 (*Callback)(
this, State,
Call,
C);
1755 if (isFreeingOwnershipAttrCall(
Call) || isAllocatingOwnershipAttrCall(
Call)) {
1756 if (isAllocatingOwnershipAttrCall(
Call))
1757 State = MallocBindRetVal(
C,
Call, State,
false);
1758 checkOwnershipAttr(State,
Call,
C);
1767 CheckerContext &
C,
const CallEvent &
Call,
const unsigned IndexOfSizeArg,
1772 const Expr *Arg =
nullptr;
1774 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1775 Arg = CE->
getArg(IndexOfSizeArg);
1776 }
else if (
const CXXNewExpr *NE =
1777 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1778 if (
NE->isArray()) {
1779 Arg = *
NE->getArraySize();
1784 assert(
false &&
"not a CallExpr or CXXNewExpr");
1789 RetVal = State->getSVal(
Call.getOriginExpr(),
C.getStackFrame());
1794 State->getSVal(Arg,
Call.getStackFrame()).getAs<DefinedSVal>();
1801 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1805 std::tie(TrueState, FalseState) =
1806 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal,
Zero));
1808 if (TrueState && !FalseState) {
1809 SymbolRef Sym = RetVal->getAsLocSymbol();
1813 const RefState *RS = State->get<RegionState>(Sym);
1815 if (RS->isAllocated())
1816 return TrueState->set<RegionState>(
1817 Sym, RefState::getAllocatedOfSizeZero(RS));
1824 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1834 while (!PointeeType.isNull()) {
1836 PointeeType = PointeeType->getPointeeType();
1849 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1855 for (
const auto *CtorParam : CtorD->
parameters()) {
1858 if (CtorParamPointeeT.
isNull())
1871MallocChecker::processNewAllocation(
const CXXAllocatorCall &
Call,
1873 AllocationFamily Family)
const {
1877 const CXXNewExpr *
NE =
Call.getOriginExpr();
1878 const ParentMap &PM =
C.getStackFrame()->getParentMap();
1892 SVal
Target =
Call.getObjectUnderConstruction();
1893 if (
Call.getOriginExpr()->isArray()) {
1894 if (
auto SizeEx =
NE->getArraySize())
1895 checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1896 AllocationFamily(AF_CXXNewArray));
1900 State = ProcessZeroAllocCheck(
C,
Call, 0, State,
Target);
1904void MallocChecker::checkNewAllocator(
const CXXAllocatorCall &
Call,
1905 CheckerContext &
C)
const {
1906 if (!
C.wasInlined) {
1909 AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1911 C.addTransition(State);
1921 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1922 return FirstSlot ==
"dataWithBytesNoCopy" ||
1923 FirstSlot ==
"initWithBytesNoCopy" ||
1924 FirstSlot ==
"initWithCharactersNoCopy";
1931 for (
unsigned i = 1; i < S.
getNumArgs(); ++i)
1933 return !
Call.getArgSVal(i).isZeroConstant();
1935 return std::nullopt;
1938void MallocChecker::checkPostObjCMessage(
const ObjCMethodCall &
Call,
1939 CheckerContext &
C)
const {
1950 if (
Call.hasNonZeroCallbackArg())
1953 bool IsKnownToBeAllocatedMemory;
1955 true, IsKnownToBeAllocatedMemory,
1956 AllocationFamily(AF_Malloc),
1959 C.addTransition(State);
1963MallocChecker::MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
1964 const OwnershipAttr *Att,
1969 auto attrClassName = Att->getModule()->getName();
1970 auto Family = AllocationFamily(AF_Custom, attrClassName);
1972 if (!Att->args().empty()) {
1973 return MallocMemAux(
C,
Call,
1974 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1975 UnknownVal(), State, Family);
1977 return MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State, Family);
1981 const CallEvent &
Call,
1983 bool isAlloca)
const {
1984 const Expr *CE =
Call.getOriginExpr();
1990 unsigned Count =
C.blockCount();
1991 SValBuilder &SVB =
C.getSValBuilder();
1992 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
1993 DefinedSVal RetVal =
1997 return State->BindExpr(CE,
C.getStackFrame(), RetVal);
2001 const CallEvent &
Call,
2002 const Expr *SizeEx, SVal
Init,
2004 AllocationFamily Family)
const {
2009 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
2012void MallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRef State,
2014 llvm::ArrayRef<SymbolRef> TaintedSyms,
2015 AllocationFamily Family)
const {
2016 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State,
this)) {
2018 std::make_unique<PathSensitiveBugReport>(TaintedAllocChecker, Msg, N);
2019 for (
const auto *TaintedSym : TaintedSyms) {
2020 R->markInteresting(TaintedSym);
2022 C.emitReport(std::move(R));
2026void MallocChecker::checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
2028 AllocationFamily Family)
const {
2031 std::vector<SymbolRef> TaintedSyms =
2033 if (TaintedSyms.empty())
2036 SValBuilder &SVB =
C.getSValBuilder();
2042 const llvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
2044 SVB.
makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));
2045 std::optional<NonLoc> SizeNL = SizeSVal.
getAs<NonLoc>();
2046 auto Cmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
2047 .
getAs<DefinedOrUnknownSVal>();
2050 auto [StateTooLarge, StateNotTooLarge] = State->assume(*
Cmp);
2051 if (!StateTooLarge && StateNotTooLarge) {
2056 std::string
Callee =
"Memory allocation function";
2057 if (
Call.getCalleeIdentifier())
2058 Callee =
Call.getCalleeIdentifier()->getName().str();
2060 Callee +
" is called with a tainted (potentially attacker controlled) "
2061 "value. Make sure the value is bound checked.",
2062 State,
C, TaintedSyms, Family);
2066 const CallEvent &
Call, SVal Size,
2068 AllocationFamily Family)
const {
2072 const Expr *CE =
Call.getOriginExpr();
2077 "Allocation functions must return a pointer");
2079 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
2080 SVal RetVal = State->getSVal(CE,
C.getStackFrame());
2084 State = State->bindDefaultInitial(RetVal,
Init, SF);
2088 Size = UnknownVal();
2090 checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
2094 Size.castAs<DefinedOrUnknownSVal>());
2100MallocChecker::FailedAlloc(CheckerContext &
C,
const CallEvent &
Call,
2102 llvm::ArrayRef<unsigned> SizeArgIndexes)
const {
2103 if (!State || !ModelAllocationFailure)
2106 for (
unsigned SizeArgI : SizeArgIndexes) {
2107 auto DefArgVal =
Call.getArgSVal(SizeArgI).getAs<DefinedOrUnknownSVal>();
2110 State = State->assume(*DefArgVal,
true);
2115 auto RetVal = State->getSVal(
Call.getOriginExpr(),
C.getStackFrame())
2116 .castAs<DefinedOrUnknownSVal>();
2117 return State->assume(RetVal,
false);
2122 AllocationFamily Family,
2123 std::optional<SVal> RetVal) {
2129 RetVal = State->getSVal(E,
C.getStackFrame());
2132 if (!RetVal->getAs<
Loc>())
2135 SymbolRef Sym = RetVal->getAsLocSymbol();
2143 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
2149 const CallEvent &
Call,
2150 const OwnershipAttr *Att,
2155 auto attrClassName = Att->getModule()->getName();
2156 auto Family = AllocationFamily(AF_Custom, attrClassName);
2158 bool IsKnownToBeAllocated =
false;
2160 for (
const auto &Arg : Att->args()) {
2162 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
2163 Att->getOwnKind() == OwnershipAttr::Holds,
2164 IsKnownToBeAllocated, Family);
2172 const CallEvent &
Call,
2174 bool Hold,
bool &IsKnownToBeAllocated,
2175 AllocationFamily Family,
2176 bool ReturnsNullOnFailure)
const {
2180 if (
Call.getNumArgs() < (
Num + 1))
2183 return FreeMemAux(
C,
Call.getArgExpr(
Num),
Call, State, Hold,
2184 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2191 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
2193 assert(*Ret &&
"We should not store the null return symbol");
2196 RetStatusSymbol = *Ret;
2204 const CallExpr *CE = dyn_cast<CallExpr>(E);
2215 if (I->getOwnKind() != OwnershipAttr::Takes)
2218 os <<
", which takes ownership of '" << I->getModule()->getName() <<
'\'';
2224 if (
const CallExpr *CE = dyn_cast<CallExpr>(E)) {
2240 if (Msg->isInstanceMessage())
2244 Msg->getSelector().print(os);
2248 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
2267 switch (Family.Kind) {
2274 case AF_CXXNewArray:
2277 case AF_IfNameIndex:
2278 os <<
"'if_nameindex()'";
2280 case AF_InnerBuffer:
2281 os <<
"container-specific allocator";
2284 os << Family.CustomName.value();
2288 assert(
false &&
"not a deallocation expression");
2293 switch (Family.Kind) {
2300 case AF_CXXNewArray:
2303 case AF_IfNameIndex:
2304 os <<
"'if_freenameindex()'";
2306 case AF_InnerBuffer:
2307 os <<
"container-specific deallocator";
2310 os <<
"function that takes ownership of '" << Family.CustomName.value()
2315 assert(
false &&
"not a deallocation expression");
2320MallocChecker::FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
2322 bool Hold,
bool &IsKnownToBeAllocated,
2323 AllocationFamily Family,
bool ReturnsNullOnFailure,
2324 std::optional<SVal> ArgValOpt)
const {
2329 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2332 DefinedOrUnknownSVal location = ArgVal.
castAs<DefinedOrUnknownSVal>();
2340 std::tie(notNullState, nullState) = State->assume(location);
2341 if (nullState && !notNullState)
2350 const Expr *ParentExpr =
Call.getOriginExpr();
2369 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2370 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2375 R =
R->StripCasts();
2379 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2386 if (!
R->hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {
2395 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2401 const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(
R->getBaseRegion());
2408 const RefState *RsBase = State->get<RegionState>(SymBase);
2409 SymbolRef PreviousRetStatusSymbol =
nullptr;
2411 IsKnownToBeAllocated =
2412 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2417 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2423 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2425 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2426 SymBase, PreviousRetStatusSymbol);
2432 if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2433 RsBase->isEscaped()) {
2436 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2437 if (!DeallocMatchesAlloc) {
2439 RsBase, SymBase, Hold);
2445 RegionOffset Offset =
R->getAsOffset();
2449 const Expr *AllocExpr =
cast<Expr>(RsBase->getStmt());
2458 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2464 State = State->remove<FreeReturnValue>(SymBase);
2468 if (ReturnsNullOnFailure) {
2469 SVal RetVal =
C.getSVal(ParentExpr);
2471 if (RetStatusSymbol) {
2472 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2473 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2481 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2486 State = State->invalidateRegions({location},
Call.getCFGElementRef(),
2487 C.blockCount(),
C.getStackFrame(),
2493 return State->set<RegionState>(SymBase,
2494 RefState::getRelinquished(Family,
2497 return State->set<RegionState>(SymBase,
2498 RefState::getReleased(Family, ParentExpr));
2502const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family)
const {
2503 switch (Family.Kind) {
2507 case AF_IfNameIndex:
2508 return MallocChecker.getAs<
T>();
2510 case AF_CXXNewArray: {
2511 const T *ND = NewDeleteChecker.getAs<
T>();
2512 const T *NDL = NewDeleteLeaksChecker.getAs<
T>();
2515 if constexpr (std::is_same_v<T, CheckerFrontend>) {
2516 assert(ND && NDL &&
"Casting to CheckerFrontend always succeeds");
2518 return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;
2520 assert(!(ND && NDL) &&
2521 "NewDelete and NewDeleteLeaks must not share a bug type");
2522 return ND ? ND : NDL;
2524 case AF_InnerBuffer:
2525 return InnerPointerChecker.getAs<
T>();
2527 assert(
false &&
"no family");
2530 assert(
false &&
"unhandled family");
2534const T *MallocChecker::getRelevantFrontendAs(CheckerContext &
C,
2536 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2537 return MallocChecker.
getAs<
T>();
2539 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2541 return getRelevantFrontendAs<T>(RS->getAllocationFamily());
2544bool MallocChecker::SummarizeValue(raw_ostream &os, SVal
V) {
2545 if (std::optional<nonloc::ConcreteInt> IntVal =
2546 V.getAs<nonloc::ConcreteInt>())
2547 os <<
"an integer (" << IntVal->getValue() <<
")";
2548 else if (std::optional<loc::ConcreteInt> ConstAddr =
2549 V.getAs<loc::ConcreteInt>())
2550 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2551 else if (std::optional<loc::GotoLabel> Label =
V.getAs<loc::GotoLabel>())
2552 os <<
"the address of the label '" << Label->getLabel()->getName() <<
"'";
2559bool MallocChecker::SummarizeRegion(
ProgramStateRef State, raw_ostream &os,
2560 const MemRegion *MR) {
2562 case MemRegion::FunctionCodeRegionKind: {
2565 os <<
"the address of the function '" << *FD <<
'\'';
2567 os <<
"the address of a function";
2570 case MemRegion::BlockCodeRegionKind:
2573 case MemRegion::BlockDataRegionKind:
2581 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2589 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2591 os <<
"the address of a local stack variable";
2596 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2604 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2606 os <<
"the address of a parameter";
2611 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2620 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2622 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2624 os <<
"the address of a global variable";
2633void MallocChecker::HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal,
2635 const Expr *DeallocExpr,
2636 AllocationFamily Family)
const {
2637 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2640 if (!Frontend->isEnabled()) {
2645 if (ExplodedNode *N =
C.generateErrorNode()) {
2646 SmallString<100> buf;
2647 llvm::raw_svector_ostream os(buf);
2650 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2651 MR = ER->getSuperRegion();
2653 os <<
"Argument to ";
2655 os <<
"deallocator";
2659 MR ? SummarizeRegion(
C.getState(), os, MR) : SummarizeValue(os, ArgVal);
2661 os <<
", which is not memory allocated by ";
2663 os <<
"not memory allocated by ";
2667 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2669 R->markInteresting(MR);
2671 C.emitReport(std::move(R));
2675void MallocChecker::HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
2676 SourceRange Range)
const {
2677 const FreeAlloca *Frontend;
2679 if (MallocChecker.isEnabled())
2680 Frontend = &MallocChecker;
2681 else if (MismatchedDeallocatorChecker.isEnabled())
2682 Frontend = &MismatchedDeallocatorChecker;
2688 if (ExplodedNode *N =
C.generateErrorNode()) {
2689 auto R = std::make_unique<PathSensitiveBugReport>(
2690 Frontend->FreeAllocaBug,
2691 "Memory allocated by 'alloca()' should not be deallocated", N);
2694 C.emitReport(std::move(R));
2698void MallocChecker::HandleMismatchedDealloc(CheckerContext &
C,
2700 const Expr *DeallocExpr,
2702 bool OwnershipTransferred)
const {
2703 if (!MismatchedDeallocatorChecker.isEnabled()) {
2708 if (ExplodedNode *N =
C.generateErrorNode()) {
2709 SmallString<100> buf;
2710 llvm::raw_svector_ostream os(buf);
2712 const Expr *AllocExpr =
cast<Expr>(RS->getStmt());
2713 SmallString<20> AllocBuf;
2714 llvm::raw_svector_ostream AllocOs(AllocBuf);
2715 SmallString<20> DeallocBuf;
2716 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2718 if (OwnershipTransferred) {
2720 os << DeallocOs.str() <<
" cannot";
2724 os <<
" take ownership of memory";
2727 os <<
" allocated by " << AllocOs.str();
2731 os <<
" allocated by " << AllocOs.str();
2733 os <<
" should be deallocated by ";
2737 os <<
", not " << DeallocOs.str();
2742 auto R = std::make_unique<PathSensitiveBugReport>(
2743 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);
2744 R->markInteresting(Sym);
2746 R->addVisitor<MallocBugVisitor>(Sym);
2747 C.emitReport(std::move(R));
2751void MallocChecker::HandleOffsetFree(CheckerContext &
C, SVal ArgVal,
2752 SourceRange Range,
const Expr *DeallocExpr,
2753 AllocationFamily Family,
2754 const Expr *AllocExpr)
const {
2755 const OffsetFree *Frontend = getRelevantFrontendAs<OffsetFree>(Family);
2758 if (!Frontend->isEnabled()) {
2763 ExplodedNode *N =
C.generateErrorNode();
2767 SmallString<100> buf;
2768 llvm::raw_svector_ostream os(buf);
2769 SmallString<20> AllocNameBuf;
2770 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2773 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2779 "Only symbols with a valid offset can have offset free errors");
2781 int offsetBytes = Offset.
getOffset() /
C.getASTContext().getCharWidth();
2783 os <<
"Argument to ";
2785 os <<
"deallocator";
2786 os <<
" is offset by "
2789 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2790 <<
" from the start of ";
2792 os <<
"memory allocated by " << AllocNameOs.str();
2794 os <<
"allocated memory";
2796 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->OffsetFreeBug,
2800 C.emitReport(std::move(R));
2803void MallocChecker::HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
2805 const UseFree *Frontend = getRelevantFrontendAs<UseFree>(
C, Sym);
2808 if (!Frontend->isEnabled()) {
2813 if (ExplodedNode *N =
C.generateErrorNode()) {
2814 AllocationFamily AF =
2815 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2817 auto R = std::make_unique<PathSensitiveBugReport>(
2818 Frontend->UseFreeBug,
2819 AF.Kind == AF_InnerBuffer
2820 ?
"Inner pointer of container used after re/deallocation"
2821 :
"Use of memory after it is released",
2824 R->markInteresting(Sym);
2826 R->addVisitor<MallocBugVisitor>(Sym);
2828 if (AF.Kind == AF_InnerBuffer)
2831 C.emitReport(std::move(R));
2835void MallocChecker::HandleDoubleFree(CheckerContext &
C, SourceRange Range,
2838 const DoubleFree *Frontend = getRelevantFrontendAs<DoubleFree>(
C, Sym);
2841 if (!Frontend->isEnabled()) {
2846 if (ExplodedNode *N =
C.generateErrorNode()) {
2847 auto R = std::make_unique<PathSensitiveBugReport>(
2848 Frontend->DoubleFreeBug,
2849 (Released ?
"Attempt to release already released memory"
2850 :
"Attempt to release non-owned memory"),
2852 if (
Range.isValid())
2854 R->markInteresting(Sym);
2856 R->markInteresting(PrevSym);
2857 R->addVisitor<MallocBugVisitor>(Sym);
2858 C.emitReport(std::move(R));
2862void MallocChecker::HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
2864 const UseZeroAllocated *Frontend =
2865 getRelevantFrontendAs<UseZeroAllocated>(
C, Sym);
2868 if (!Frontend->isEnabled()) {
2873 if (ExplodedNode *N =
C.generateErrorNode()) {
2874 auto R = std::make_unique<PathSensitiveBugReport>(
2875 Frontend->UseZeroAllocatedBug,
"Use of memory allocated with size zero",
2880 R->markInteresting(Sym);
2881 R->addVisitor<MallocBugVisitor>(Sym);
2883 C.emitReport(std::move(R));
2887void MallocChecker::HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal,
2889 const Expr *FreeExpr,
2890 AllocationFamily Family)
const {
2891 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2894 if (!Frontend->isEnabled()) {
2899 if (ExplodedNode *N =
C.generateErrorNode()) {
2900 SmallString<100> Buf;
2901 llvm::raw_svector_ostream Os(Buf);
2904 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2905 MR = ER->getSuperRegion();
2907 Os <<
"Argument to ";
2909 Os <<
"deallocator";
2911 Os <<
" is a function pointer";
2913 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2915 R->markInteresting(MR);
2917 C.emitReport(std::move(R));
2922MallocChecker::ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
2924 AllocationFamily Family,
bool SuffixWithN)
const {
2933 const Expr *arg0Expr = CE->
getArg(0);
2934 SVal Arg0Val =
C.getSVal(arg0Expr);
2937 DefinedOrUnknownSVal arg0Val = Arg0Val.
castAs<DefinedOrUnknownSVal>();
2939 SValBuilder &svalBuilder =
C.getSValBuilder();
2941 DefinedOrUnknownSVal PtrEQ = svalBuilder.
evalEQ(
2942 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2945 const Expr *Arg1 = CE->
getArg(1);
2948 SVal TotalSize =
C.getSVal(Arg1);
2950 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2955 DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(
2956 State, TotalSize.
castAs<DefinedOrUnknownSVal>(),
2957 svalBuilder.makeIntValWithWidth(
2958 svalBuilder.getContext().getCanonicalSizeType(), 0));
2961 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2963 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2966 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2967 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2971 if (PrtIsNull && !SizeIsZero) {
2973 C,
Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
2978 if (PrtIsNull && SizeIsZero)
2983 bool IsKnownToBeAllocated =
false;
2992 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2997 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
3000 MallocMemAux(
C,
Call, TotalSize, UnknownVal(), stateFree, Family);
3004 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
3005 if (ShouldFreeOnFail)
3006 Kind = OAR_FreeOnFailure;
3007 else if (!IsKnownToBeAllocated)
3008 Kind = OAR_DoNotTrackAfterFailure;
3012 SVal RetVal = stateRealloc->getSVal(CE,
C.getStackFrame());
3014 assert(FromPtr && ToPtr &&
3015 "By this point, FreeMemAux and MallocMemAux should have checked "
3016 "whether the argument or the return value is symbolic!");
3020 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
3021 ReallocPair(FromPtr, Kind));
3023 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
3024 return stateRealloc;
3030 const CallEvent &
Call,
3035 if (
Call.getNumArgs() < 2)
3038 SValBuilder &svalBuilder =
C.getSValBuilder();
3041 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
3043 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State,
3044 AllocationFamily(AF_Malloc));
3047MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
3049 CheckerContext &
C) {
3053 const ExplodedNode *AllocNode = N;
3054 const MemRegion *ReferenceRegion =
nullptr;
3058 if (!State->get<RegionState>(Sym))
3063 if (!ReferenceRegion) {
3064 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
3065 SVal Val = State->getSVal(MR);
3071 ReferenceRegion = MR;
3079 if (NSF == LeakStackFrame || NSF->
isParentOf(LeakStackFrame))
3084 return LeakInfo(AllocNode, ReferenceRegion);
3087void MallocChecker::HandleLeak(
SymbolRef Sym, ExplodedNode *N,
3088 CheckerContext &
C)
const {
3089 assert(N &&
"HandleLeak is only called with a non-null node");
3091 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3092 assert(RS &&
"cannot leak an untracked symbol");
3093 AllocationFamily Family = RS->getAllocationFamily();
3095 if (Family.Kind == AF_Alloca)
3098 const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);
3102 if (!Frontend || !Frontend->isEnabled())
3108 PathDiagnosticLocation LocUsedForUniqueing;
3109 const ExplodedNode *AllocNode =
nullptr;
3110 const MemRegion *Region =
nullptr;
3111 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
3116 AllocationStmt,
C.getSourceManager(), AllocNode->
getStackFrame());
3118 SmallString<200> buf;
3119 llvm::raw_svector_ostream os(buf);
3121 os <<
"Potential leak of memory pointed to by ";
3124 os <<
"Potential memory leak";
3127 auto R = std::make_unique<PathSensitiveBugReport>(
3128 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3130 R->markInteresting(Sym);
3131 R->addVisitor<MallocBugVisitor>(Sym,
true);
3132 if (ShouldRegisterNoOwnershipChangeVisitor)
3133 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
3134 C.emitReport(std::move(R));
3137void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3138 CheckerContext &
C)
const
3141 RegionStateTy OldRS = state->get<RegionState>();
3142 RegionStateTy::Factory &F = state->get_context<RegionState>();
3144 RegionStateTy RS = OldRS;
3145 SmallVector<SymbolRef, 2> Errors;
3146 for (
auto [Sym, State] : RS) {
3147 if (SymReaper.
isDead(Sym)) {
3148 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3149 Errors.push_back(Sym);
3151 RS = F.remove(RS, Sym);
3157 assert(state->get<ReallocPairs>() ==
3158 C.getState()->get<ReallocPairs>());
3159 assert(state->get<FreeReturnValue>() ==
3160 C.getState()->get<FreeReturnValue>());
3165 ReallocPairsTy RP = state->get<ReallocPairs>();
3166 for (
auto [Sym, ReallocPair] : RP) {
3167 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
3168 state = state->remove<ReallocPairs>(Sym);
3173 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3174 for (
auto [Sym, RetSym] : FR) {
3175 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
3176 state = state->remove<FreeReturnValue>(Sym);
3181 ExplodedNode *N =
C.getPredecessor();
3182 if (!Errors.empty()) {
3183 N =
C.generateNonFatalErrorNode(
C.getState());
3186 HandleLeak(Sym, N,
C);
3191 C.addTransition(state->set<RegionState>(RS), N);
3198 return Name ==
"unique_ptr" || Name ==
"shared_ptr";
3205 if (
const auto *TST = QT->
getAs<TemplateSpecializationType>()) {
3206 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
3229 llvm::SmallPtrSetImpl<const MemRegion *> *
Out;
3232 llvm::SmallPtrSetImpl<const MemRegion *> &
Out)
3245 C->getState()->getLValue(BaseDecl,
Reg->getAs<
SubRegion>(), IsVirtual);
3250 return std::nullopt;
3266 std::optional<FieldConsumer> FC = std::nullopt) {
3279 BaseSpec.getType()->getAsCXXRecordDecl()) {
3280 std::optional<FieldConsumer> NewFC;
3282 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());
3300 if (!
T->isRecordType() ||
T->isReferenceType())
3332 const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(
Call.getDecl());
3336 const auto *RD = CD->getParent();
3341 for (
const auto *Param : CD->parameters()) {
3342 QualType ParamType = Param->getType();
3357 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {
3374 for (
unsigned I = 0, E = std::min(
Call.getNumArgs(), CD->getNumParams());
3376 const Expr *ArgExpr =
Call.getArgExpr(I);
3380 QualType ParamType = CD->getParamDecl(I)->
getType();
3384 SVal ArgVal =
Call.getArgSVal(I);
3386 if (Sym && State->contains<RegionState>(Sym)) {
3387 const RefState *RS = State->get<RegionState>(Sym);
3388 if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {
3389 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3405 return handleSmartPointerConstructorArguments(
Call, State);
3409 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;
3410 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3411 const Expr *AE =
Call.getArgExpr(I);
3420 SVal ArgVal =
Call.getArgSVal(I);
3421 const MemRegion *ArgRegion = ArgVal.
getAsRegion();
3424 SmartPtrFieldRoots);
3428 if (!SmartPtrFieldRoots.empty()) {
3429 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(
3430 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());
3431 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(
3432 SmartPtrFieldRootsVec, State);
3438void MallocChecker::checkPostCall(
const CallEvent &
Call,
3439 CheckerContext &
C)
const {
3441 if (
const auto *PostFN = PostFnMap.
lookup(
Call)) {
3442 (*PostFN)(
this,
C.getState(),
Call,
C);
3447 C.addTransition(handleSmartPointerRelatedCalls(
Call,
C,
C.getState()));
3450void MallocChecker::checkPreCall(
const CallEvent &
Call,
3451 CheckerContext &
C)
const {
3453 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3454 const CXXDeleteExpr *DE = DC->getOriginExpr();
3460 if (!NewDeleteChecker.isEnabled())
3468 bool IsKnownToBeAllocated;
3471 false, IsKnownToBeAllocated,
3472 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3474 C.addTransition(State);
3485 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3486 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3490 HandleDoubleFree(
C, SourceRange(),
true, Sym,
3498 if (
const auto *PreFN = PreFnMap.
lookup(
Call)) {
3499 (*PreFN)(
this,
C.getState(),
Call,
C);
3507 if (
const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&
Call)) {
3508 const FunctionDecl *FD = FC->getDecl();
3515 if (MallocChecker.isEnabled() && isFreeingCall(
Call))
3520 if (
const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&
Call)) {
3521 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3522 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3527 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3528 SVal ArgSVal =
Call.getArgSVal(I);
3533 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3539void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3540 CheckerContext &
C)
const {
3541 checkEscapeOnReturn(S,
C);
3547void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3548 CheckerContext &
C)
const {
3549 checkEscapeOnReturn(S,
C);
3552void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3553 CheckerContext &
C)
const {
3562 SVal RetVal =
C.getSVal(E);
3569 if (
const SymbolicRegion *BMR =
3571 Sym = BMR->getSymbol();
3575 checkUseAfterFree(Sym,
C, E);
3581void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3582 CheckerContext &
C)
const {
3590 const BlockDataRegion *
R =
3593 auto ReferencedVars =
R->referenced_vars();
3594 if (ReferencedVars.empty())
3597 SmallVector<const MemRegion *, 10> Regions;
3598 MemRegionManager &MemMgr =
C.getSValBuilder().getRegionManager();
3600 for (
const auto &Var : ReferencedVars) {
3601 const VarRegion *VR = Var.getCapturedRegion();
3605 Regions.push_back(VR);
3609 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3610 C.addTransition(state);
3615 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3616 return (RS && RS->isReleased());
3619bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3620 const CallEvent &
Call, CheckerContext &
C)
const {
3621 if (
Call.getNumArgs() == 0)
3624 StringRef FunctionStr =
"";
3625 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3626 if (
const Stmt *Body = FD->
getBody())
3631 C.getSourceManager(),
C.getLangOpts());
3634 if (!FunctionStr.contains(
"__isl_"))
3640 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3641 if (
const RefState *RS = State->get<RegionState>(Sym))
3642 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3644 C.addTransition(State);
3648bool MallocChecker::checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
3649 const Stmt *S)
const {
3659void MallocChecker::checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
3660 const Stmt *S)
const {
3663 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3664 if (RS->isAllocatedOfSizeZero())
3665 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3667 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3673void MallocChecker::checkLocation(SVal l,
bool isLoad,
const Stmt *S,
3674 CheckerContext &
C)
const {
3677 checkUseAfterFree(Sym,
C, S);
3678 checkUseZeroAllocated(Sym,
C, S);
3686 bool Assumption)
const {
3687 RegionStateTy RS = state->get<RegionState>();
3688 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3690 ConstraintManager &CMgr = state->getConstraintManager();
3691 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3693 state = state->remove<RegionState>(Sym);
3698 ReallocPairsTy RP = state->get<ReallocPairs>();
3699 for (
auto [Sym, ReallocPair] : RP) {
3701 ConstraintManager &CMgr = state->getConstraintManager();
3702 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3706 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3707 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3708 if (RS->isReleased()) {
3709 switch (ReallocPair.Kind) {
3710 case OAR_ToBeFreedAfterFailure:
3711 state = state->set<RegionState>(ReallocSym,
3712 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3714 case OAR_DoNotTrackAfterFailure:
3715 state = state->remove<RegionState>(ReallocSym);
3718 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3722 state = state->remove<ReallocPairs>(Sym);
3728bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3729 const CallEvent *
Call,
3733 EscapingSymbol =
nullptr;
3743 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(
Call)) {
3746 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3759 return *FreeWhenDone;
3765 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3766 if (FirstSlot.ends_with(
"NoCopy"))
3773 if (FirstSlot.starts_with(
"addPointer") ||
3774 FirstSlot.starts_with(
"insertPointer") ||
3775 FirstSlot.starts_with(
"replacePointer") ||
3776 FirstSlot ==
"valueWithPointer") {
3783 if (Msg->getMethodFamily() ==
OMF_init) {
3784 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3800 if (isMemCall(*
Call))
3804 if (!
Call->isInSystemHeader())
3811 StringRef FName = II->
getName();
3815 if (FName.ends_with(
"NoCopy")) {
3819 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3820 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3821 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3822 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3823 if (DeallocatorName ==
"kCFAllocatorNull")
3834 if (FName ==
"funopen")
3835 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3841 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3842 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3843 if (
Call->getNumArgs() >= 1) {
3845 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3846 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3847 if (D->getCanonicalDecl()->getName().contains(
"std"))
3857 if (FName ==
"CGBitmapContextCreate" ||
3858 FName ==
"CGBitmapContextCreateWithData" ||
3859 FName ==
"CVPixelBufferCreateWithBytes" ||
3860 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3861 FName ==
"OSAtomicEnqueue") {
3865 if (FName ==
"postEvent" &&
3870 if (FName ==
"connectImpl" &&
3875 if (FName ==
"singleShotImpl" &&
3885 if (FName ==
"GetOwnedMessageInternal") {
3893 if (
Call->argumentsMayEscape())
3903 const CallEvent *
Call,
3905 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3911 const CallEvent *
Call,
3914 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3919 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3920 RS->getAllocationFamily().Kind == AF_CXXNew);
3926 bool IsConstPointerEscape)
const {
3931 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3938 if (EscapingSymbol && EscapingSymbol != sym)
3941 if (
const RefState *RS = State->get<RegionState>(sym))
3942 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3944 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3949bool MallocChecker::isArgZERO_SIZE_PTR(
ProgramStateRef State, CheckerContext &
C,
3950 SVal ArgVal)
const {
3951 if (!KernelZeroSizePtrValue)
3952 KernelZeroSizePtrValue =
3955 const llvm::APSInt *ArgValKnown =
3956 C.getSValBuilder().getKnownValue(State, ArgVal);
3957 return ArgValKnown && *KernelZeroSizePtrValue &&
3958 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3963 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3964 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3966 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3968 if (!currMap.lookup(sym))
3978 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3979 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3980 N.contains_insensitive(
"intrusive") ||
3981 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3990 BugReporterContext &BRC,
3991 PathSensitiveBugReport &BR) {
3995 const RefState *RSCurr = state->get<RegionState>(Sym);
3996 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
4001 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
4014 if (ReleaseFunctionSF && (ReleaseFunctionSF == CurrentSF ||
4016 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
4019 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
4020 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
4026 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
4029 if (
const auto *MD =
4031 const CXXRecordDecl *RD = MD->getParent();
4049 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
4050 SmallString<256> Buf;
4051 llvm::raw_svector_ostream
OS(Buf);
4054 if (isAllocated(RSCurr, RSPrev, S)) {
4055 Msg =
"Memory is allocated";
4056 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4057 Sym,
"Returned allocated memory");
4059 const auto Family = RSCurr->getAllocationFamily();
4060 switch (Family.Kind) {
4065 case AF_CXXNewArray:
4066 case AF_IfNameIndex:
4067 Msg =
"Memory is released";
4068 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4069 Sym,
"Returning; memory was released");
4071 case AF_InnerBuffer: {
4072 const MemRegion *ObjRegion =
4075 QualType ObjTy = TypedRegion->getValueType();
4076 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
4079 OS <<
"deallocated by call to destructor";
4080 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4081 Sym,
"Returning; inner buffer was deallocated");
4083 OS <<
"reallocated by call to '";
4084 const Stmt *S = RSCurr->getStmt();
4085 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
4086 OS << MemCallE->getMethodDecl()->getDeclName();
4087 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
4088 OS << OpCallE->getDirectCallee()->getDeclName();
4089 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
4091 CallEventRef<>
Call =
4093 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
4094 OS << D->getDeclName();
4099 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4100 Sym,
"Returning; inner buffer was reallocated");
4106 assert(
false &&
"Unhandled allocation family!");
4116 ReleaseFunctionSF = CurrentSF;
4120 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(SF.
getDecl())) {
4156 ReleaseFunctionSF = &SF;
4160 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
4161 Msg =
"Memory ownership is transferred";
4162 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
4163 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
4164 Mode = ReallocationFailed;
4165 Msg =
"Reallocation failed";
4166 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
4167 Sym,
"Reallocation failed");
4171 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
4172 "We only support one failed realloc at a time.");
4174 FailedReallocSymbol = sym;
4179 }
else if (Mode == ReallocationFailed) {
4180 assert(FailedReallocSymbol &&
"No symbol to look for.");
4183 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
4185 Msg =
"Attempt to reallocate memory";
4186 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4187 Sym,
"Returned reallocated memory");
4188 FailedReallocSymbol =
nullptr;
4201 PathDiagnosticLocation Pos;
4203 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
4207 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
4213 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
4218void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
4219 const char *NL,
const char *Sep)
const {
4221 RegionStateTy RS = State->get<RegionState>();
4223 if (!RS.isEmpty()) {
4224 Out << Sep <<
"MallocChecker :" << NL;
4225 for (
auto [Sym,
Data] : RS) {
4226 const RefState *RefS = State->get<RegionState>(Sym);
4227 AllocationFamily Family = RefS->getAllocationFamily();
4229 const CheckerFrontend *Frontend =
4230 getRelevantFrontendAs<CheckerFrontend>(Family);
4244namespace allocation_state {
4248 AllocationFamily Family(AF_InnerBuffer);
4249 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
4259 Mgr.
getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);
4267 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
4269 Chk->ShouldRegisterNoOwnershipChangeVisitor =
4271 DMMName,
"AddNoOwnershipChangeNotes");
4272 Chk->ModelAllocationFailure =
4274 DMMName,
"ModelAllocationFailure");
4277bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
4281#define REGISTER_CHECKER(NAME) \
4282 void ento::register##NAME(CheckerManager &Mgr) { \
4283 Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr); \
4286 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
4295#undef REGISTER_CHECKER
#define REGISTER_CHECKER(name)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
Result
Implement __builtin_bit_cast and related operations.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::Target Target
static bool isRvalueByValueRecordWithSmartPtr(const Expr *AE)
Check if an expression is an rvalue record with smart owning pointer fields passed by value.
static bool isFromStdNamespace(const CallEvent &Call)
static bool isStandardNew(const FunctionDecl *FD)
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
static QualType getDeepPointeeType(QualType T)
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)
Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.
static void collectSmartPtrFieldRegions(const MemRegion *Reg, QualType RecQT, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
Collect memory regions of smart owning pointer fields from a record type (including fields from base ...
static bool hasSmartPtrField(const CXXRecordDecl *CRD, std::optional< FieldConsumer > FC=std::nullopt)
Check if a record type has smart owning pointer fields (directly or in base classes).
static bool isStandardDelete(const FunctionDecl *FD)
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static bool isSmartPtrType(QualType QT)
static bool isStandardNewDelete(const T &FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
static bool isRvalueByValueRecord(const Expr *AE)
Check if an expression is an rvalue record type passed by value.
#define BUGTYPE_PROVIDER(NAME, DEF)
static bool isGRealloc(const CallEvent &Call)
static const Expr * getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD)
static bool isSmartPtrRecord(const CXXRecordDecl *RD)
Check if a CXXRecordDecl has a name matching recognized smart pointer names.
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)
Print expected name of a deallocator based on the allocator's family.
static bool isStandardRealloc(const CallEvent &Call)
static bool isSmartPtrCall(const CallEvent &Call)
Check if a call is a constructor of a smart owning pointer class that accepts pointer parameters.
static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)
Checks if the previous call to free on the given symbol failed - if free failed, returns true.
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)
Update the RefState to reflect the new memory allocation.
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
static bool isSmartPtrName(StringRef Name)
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
CanQualType getCanonicalSizeType() const
CanQualType UnsignedLongTy
static bool hasSameType(QualType T1, QualType T2)
Determine whether the given types T1 and T2 are equivalent.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
const BlockDecl * getBlockDecl() const
Represents a base class of a C++ class.
Represents binding an expression to a temporary.
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Represents a C++ constructor within a class.
Represents a delete expression for memory deallocation and destructor calls, e.g.
Represents a C++ destructor within a class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Represents a C++ struct/union/class.
Represents a C++ functional cast expression that builds a temporary object.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
static CharSourceRange getTokenRange(SourceRange R)
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
ASTContext & getASTContext() const LLVM_READONLY
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
SourceLocation getLocation() const
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Represents a member of a struct/union/class.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
ArrayRef< ParmVarDecl * > parameters() const
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
QualType getDeclaredReturnType() const
Get the declared return type, which may differ from the actual return type if the return type is dedu...
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Describes an C or C++ initializer list.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
An expression that sends a message to the given Objective-C object or class.
bool isConsumedExpr(Expr *E) const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
field_range fields() const
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
unsigned getNumArgs() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
bool isParentOf(const StackFrame *SF) const
const Decl * getDecl() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
The base class of all kinds of template declarations (e.g., class, function, etc.).
NamedDecl * getTemplatedDecl() const
Get the underlying, templated declaration.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isVoidPointerType() const
bool isFunctionPointerType() const
bool isPointerType() const
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
APSIntPtr getMaxValue(const llvm::APSInt &v)
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
ProgramStateManager & getStateManager() const
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
An immutable map from CallDescriptions to arbitrary data.
const T * lookup(const CallEvent &Call) const
CallEventRef getSimpleCall(const CallExpr *E, ProgramStateRef State, const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
Represents an abstract call to a function or method along a particular path.
Checker families (where a single backend class implements multiple related frontends) should derive f...
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
CheckerNameRef getName() const
const AnalyzerOptions & getAnalyzerOptions() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
const ProgramStateRef & getState() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
llvm::iterator_range< StackFrame::parent_iterator > stackframes() const
Iterates over the current stack frame and all of its ancestors.
ExplodedNode * getFirstPred()
const StackFrame * getStackFrame() const
static bool isLocType(QualType T)
const VarRegion * getVarRegion(const VarDecl *VD, const StackFrame *SF)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and StackFram...
MemRegion - The root abstract class for all memory regions.
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
Represents any expression that calls an Objective-C method.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
void addCallStackHint(PathDiagnosticPieceRef Piece, std::unique_ptr< StackHintGenerator > StackHint)
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
CallEventManager & getCallEventManager()
bool hasSymbolicOffset() const
int64_t getOffset() const
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
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.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const StackFrame *SF, unsigned Count)
Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...
DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const StackFrame *SF, QualType type, unsigned Count)
Conjure a symbol representing heap allocated memory region.
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isUnknownOrUndef() const
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
const MemRegion * getAsRegion() const
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
virtual void dumpToStream(raw_ostream &os) const
virtual QualType getType() const =0
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
SymbolRef getSymbol() const
It might return null.
const VarDecl * getDecl() const override=0
const StackFrame * getStackFrame() const
It might return null.
Defines the clang::TargetInfo interface.
__inline void unsigned int _2
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDeleteExpr > cxxDeleteExpr
Matches delete expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)
This function provides an additional visitor that augments the bug report with information relevant t...
const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)
'Sym' represents a pointer to the inner buffer of a container object.
const char *const MemoryError
const char *const TaintedData
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Expr *E, const StackFrame *SF, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given expression and state.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent)
Set the dynamic extent Extent of the region MR.
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::optional< SVal > getPointeeVal(SVal PtrSVal, ProgramStateRef State)
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool NE(InterpState &S, CodePtr OpPC)
Top level wrappers for InstallAPI frontend operations.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
bool isa(CodeGen::Address addr)
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
const FunctionProtoType * T
bool operator!=(CanQual< T > x, CanQual< U > y)
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.
U cast(CodeGen::Address addr)
@ Other
Other implicit parameter.
int const char * function
Helper struct for collecting smart owning pointer field regions.
void consume(const FieldDecl *FD)
std::optional< FieldConsumer > switchToBase(const CXXRecordDecl *BaseDecl, bool IsVirtual)
FieldConsumer(const MemRegion *Reg, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
llvm::SmallPtrSetImpl< const MemRegion * > * Out