79#include "llvm/ADT/STLExtras.h"
80#include "llvm/ADT/SetOperations.h"
81#include "llvm/ADT/SmallString.h"
82#include "llvm/ADT/StringExtras.h"
83#include "llvm/Support/Casting.h"
84#include "llvm/Support/Compiler.h"
85#include "llvm/Support/ErrorHandling.h"
86#include "llvm/Support/raw_ostream.h"
94using namespace std::placeholders;
106enum AllocationFamily {
157 AllocationFamily Family;
159 RefState(Kind k,
const Stmt *
s, AllocationFamily family)
160 : S(
s), K(k), Family(family) {
161 assert(family != AF_None);
165 bool isAllocated()
const {
return K == Allocated; }
166 bool isAllocatedOfSizeZero()
const {
return K == AllocatedOfSizeZero; }
167 bool isReleased()
const {
return K == Released; }
168 bool isRelinquished()
const {
return K == Relinquished; }
169 bool isEscaped()
const {
return K == Escaped; }
170 AllocationFamily getAllocationFamily()
const {
return Family; }
171 const Stmt *getStmt()
const {
return S; }
174 return K ==
X.K && S ==
X.S && Family ==
X.Family;
177 static RefState getAllocated(AllocationFamily family,
const Stmt *
s) {
178 return RefState(Allocated,
s, family);
180 static RefState getAllocatedOfSizeZero(
const RefState *RS) {
181 return RefState(AllocatedOfSizeZero, RS->getStmt(),
182 RS->getAllocationFamily());
184 static RefState getReleased(AllocationFamily family,
const Stmt *
s) {
185 return RefState(Released,
s, family);
187 static RefState getRelinquished(AllocationFamily family,
const Stmt *
s) {
188 return RefState(Relinquished,
s, family);
190 static RefState getEscaped(
const RefState *RS) {
191 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
194 void Profile(llvm::FoldingSetNodeID &ID)
const {
197 ID.AddInteger(Family);
200 LLVM_DUMP_METHOD
void dump(raw_ostream &OS)
const {
202#define CASE(ID) case ID: OS << #ID; break;
204 CASE(AllocatedOfSizeZero)
211 LLVM_DUMP_METHOD
void dump()
const {
dump(llvm::errs()); }
226 AllocationFamily Family,
227 std::optional<SVal> RetVal = std::nullopt);
241enum OwnershipAfterReallocKind {
243 OAR_ToBeFreedAfterFailure,
253 OAR_DoNotTrackAfterFailure
266 OwnershipAfterReallocKind
Kind;
268 ReallocPair(
SymbolRef S, OwnershipAfterReallocKind K)
269 : ReallocatedSym(S),
Kind(K) {}
270 void Profile(llvm::FoldingSetNodeID &ID)
const {
272 ID.AddPointer(ReallocatedSym);
275 return ReallocatedSym ==
X.ReallocatedSym &&
288 if (!
Call.getDecl() || !isa<FunctionDecl>(
Call.getDecl()))
300 :
public Checker<check::DeadSymbols, check::PointerEscape,
301 check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
302 check::EndFunction, check::PreCall, check::PostCall,
303 check::NewAllocator, check::PostStmt<BlockExpr>,
304 check::PostObjCMessage, check::Location, eval::Assume> {
310 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
312 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
322 CK_NewDeleteLeaksChecker,
323 CK_MismatchedDeallocatorChecker,
324 CK_InnerPointerChecker,
328 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
330 bool ChecksEnabled[CK_NumCheckKinds] = {
false};
342 bool Assumption)
const;
343 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
356 const char *NL,
const char *Sep)
const override;
359 mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];
360 mutable std::unique_ptr<BugType> BT_DoubleDelete;
361 mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];
362 mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];
363 mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
364 mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
365 mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
366 mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
367 mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
369#define CHECK_FN(NAME) \
370 void NAME(const CallEvent &Call, CheckerContext &C) const;
389 bool ShouldFreeOnFail)
const;
391 using CheckFn = std::function<void(
const MallocChecker *,
395 {{{
"free"}, 1}, &MallocChecker::checkFree},
396 {{{
"if_freenameindex"}, 1}, &MallocChecker::checkIfFreeNameIndex},
397 {{{
"kfree"}, 1}, &MallocChecker::checkFree},
398 {{{
"g_free"}, 1}, &MallocChecker::checkFree},
404 friend class NoOwnershipChangeVisitor;
407 {{{
"alloca"}, 1}, &MallocChecker::checkAlloca},
408 {{{
"_alloca"}, 1}, &MallocChecker::checkAlloca},
409 {{{
"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
410 {{{
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
411 {{{
"calloc"}, 2}, &MallocChecker::checkCalloc},
412 {{{
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
415 {{{
"_strdup"}, 1}, &MallocChecker::checkStrdup},
416 {{{
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
417 {{{
"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
420 {{{
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
421 {{{
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
422 {{{
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
423 {{{
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
424 {{{
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
425 {{{
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
426 {{{
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
427 {{{
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
428 {{{
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
433 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
435 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
true)},
437 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
438 {{{
"g_try_realloc"}, 2},
439 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
440 {{{
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
441 {{{
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
447 mutable std::optional<uint64_t> KernelZeroFlagVal;
449 using KernelZeroSizePtrValueTy = std::optional<int>;
454 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
460 AllocationFamily Family)
const;
471 ProcessZeroAllocCheck(
const CallEvent &
Call,
const unsigned IndexOfSizeArg,
473 std::optional<SVal> RetVal = std::nullopt);
523 [[nodiscard]] std::optional<ProgramStateRef>
546 const OwnershipAttr *Att,
570 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
571 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
595 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
613 bool SuffixWithN =
false)
const;
622 const Expr *BlockBytes);
634 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
643 const Stmt *S)
const;
658 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
667 bool IsConstPointerEscape)
const;
676 std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
677 bool IsALeakCheck =
false)
const;
680 bool IsALeakCheck =
false)
const;
682 static bool SummarizeValue(raw_ostream &os,
SVal V);
683 static bool SummarizeRegion(raw_ostream &os,
const MemRegion *MR);
686 const Expr *DeallocExpr,
687 AllocationFamily Family)
const;
693 const Expr *DeallocExpr,
const RefState *RS,
694 SymbolRef Sym,
bool OwnershipTransferred)
const;
697 const Expr *DeallocExpr, AllocationFamily Family,
698 const Expr *AllocExpr =
nullptr)
const;
712 const Expr *FreeExpr,
713 AllocationFamily Family)
const;
746 OwnershipBindingsHandler(
SymbolRef Sym, OwnerSet &Owners)
747 : Sym(Sym), Owners(Owners) {}
752 Owners.insert(Region);
756 LLVM_DUMP_METHOD
void dump()
const { dumpToStream(llvm::errs()); }
757 LLVM_DUMP_METHOD
void dumpToStream(llvm::raw_ostream &out)
const {
758 out <<
"Owners: {\n";
761 Owner->dumpToStream(out);
773 OwnershipBindingsHandler Handler{Sym,
Ret};
774 State->getStateManager().getStoreManager().iterBindings(State->getStore(),
779 LLVM_DUMP_METHOD
static std::string
781 if (
const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>(
784 return FD->getQualifiedNameAsString();
795 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
796 if (
Checker.FreeingMemFnMap.lookupAsWritten(
Call) ||
797 Checker.ReallocatingMemFnMap.lookupAsWritten(
Call))
800 if (
const auto *
Func =
801 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
802 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
811 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
ASTContext &ACtx) {
813 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
831 if (
const auto *
Call = Match.getNodeAs<
CallExpr>(
"call"))
832 if (isFreeingCallAsWritten(*
Call))
841 bool wasModifiedInFunction(
const ExplodedNode *CallEnterN,
843 if (!doesFnIntendToHandleOwnership(
845 CallExitEndN->
getState()->getAnalysisManager().getASTContext()))
848 if (CallEnterN->
getState()->get<RegionState>(Sym) !=
849 CallExitEndN->
getState()->get<RegionState>(Sym))
852 OwnerSet CurrOwners = getOwnersAtNode(CallEnterN);
853 OwnerSet ExitOwners = getOwnersAtNode(CallExitEndN);
861 return !llvm::set_is_subset(ExitOwners, CurrOwners);
867 N->
getState()->getStateManager().getContext().getSourceManager());
868 return std::make_shared<PathDiagnosticEventPiece>(
869 L,
"Returning without deallocating memory or storing the pointer for "
870 "later deallocation");
897 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
899 if (
V.getAsSymbol() == Sym)
910 void Profile(llvm::FoldingSetNodeID &ID)
const override {
929 enum NotificationMode {
Normal, ReallocationFailed };
935 NotificationMode Mode;
947 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
948 : Sym(S), Mode(
Normal), FailedReallocSymbol(nullptr),
949 ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
951 static void *getTag() {
956 void Profile(llvm::FoldingSetNodeID &ID)
const override {
957 ID.AddPointer(getTag());
962 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
964 return (isa_and_nonnull<CallExpr, CXXNewExpr>(
Stmt) &&
966 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
968 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
973 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
976 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
977 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(
Stmt)) ||
978 (!
Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer));
983 static inline bool isRelinquished(
const RefState *RSCurr,
984 const RefState *RSPrev,
const Stmt *
Stmt) {
986 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(
Stmt) &&
987 (RSCurr && RSCurr->isRelinquished()) &&
988 (!RSPrev || !RSPrev->isRelinquished()));
995 static inline bool hasReallocFailed(
const RefState *RSCurr,
996 const RefState *RSPrev,
998 return ((!isa_and_nonnull<CallExpr>(
Stmt)) &&
1000 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1002 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1017 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1022 class StackHintGeneratorForReallocationFailed
1025 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1028 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1033 llvm::raw_svector_ostream os(buf);
1035 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1036 <<
" parameter failed";
1038 return std::string(os.str());
1042 return "Reallocation of returned value failed";
1061 state = state->remove<RegionState>(sym);
1072 if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete &&
1073 Kind != OO_Array_Delete)
1089 if (
Func->hasAttrs()) {
1090 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1091 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1092 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1099bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1100 if (FreeingMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1103 if (
const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl()))
1104 return isFreeingOwnershipAttrCall(
Func);
1110 if (FreeingMemFnMap.lookup(
Call) || AllocatingMemFnMap.lookup(
Call) ||
1111 ReallocatingMemFnMap.lookup(
Call))
1114 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1117 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1118 return Func &&
Func->hasAttr<OwnershipAttr>();
1121std::optional<ProgramStateRef>
1143 if (!KernelZeroFlagVal) {
1145 case llvm::Triple::FreeBSD:
1146 KernelZeroFlagVal = 0x0100;
1148 case llvm::Triple::NetBSD:
1149 KernelZeroFlagVal = 0x0002;
1151 case llvm::Triple::OpenBSD:
1152 KernelZeroFlagVal = 0x0008;
1154 case llvm::Triple::Linux:
1156 KernelZeroFlagVal = 0x8000;
1164 return std::nullopt;
1171 if (
Call.getNumArgs() < 2)
1172 return std::nullopt;
1174 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1175 const SVal V =
C.getSVal(FlagsEx);
1176 if (!isa<NonLoc>(
V)) {
1179 return std::nullopt;
1183 NonLoc ZeroFlag =
C.getSValBuilder()
1184 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1186 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1190 return std::nullopt;
1195 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1198 if (TrueState && !FalseState) {
1199 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1200 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1204 return std::nullopt;
1208 const Expr *BlockBytes) {
1210 SVal BlocksVal =
C.getSVal(Blocks);
1211 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1213 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1223 State = ProcessZeroAllocCheck(
Call, 0, State);
1224 C.addTransition(State);
1230 std::optional<ProgramStateRef> MaybeState =
1231 performKernelMalloc(
Call,
C, State);
1233 State = *MaybeState;
1237 C.addTransition(State);
1245 if (isa<CXXMethodDecl>(FD))
1259 if (isa<CXXMethodDecl>(FD))
1269 bool ShouldFreeOnFail)
const {
1279 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State, AF_Malloc);
1280 State = ProcessZeroAllocCheck(
Call, 1, State);
1281 C.addTransition(State);
1287 State = CallocMem(
C,
Call, State);
1288 State = ProcessZeroAllocCheck(
Call, 0, State);
1289 State = ProcessZeroAllocCheck(
Call, 1, State);
1290 C.addTransition(State);
1295 bool IsKnownToBeAllocatedMemory =
false;
1296 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1298 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1300 C.addTransition(State);
1308 State = ProcessZeroAllocCheck(
Call, 0, State);
1309 C.addTransition(State);
1315 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1320 C.addTransition(State);
1331 C.addTransition(State);
1334void MallocChecker::checkIfFreeNameIndex(
const CallEvent &
Call,
1337 bool IsKnownToBeAllocatedMemory =
false;
1338 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1340 C.addTransition(State);
1343void MallocChecker::checkCXXNewOrCXXDelete(
const CallEvent &
Call,
1346 bool IsKnownToBeAllocatedMemory =
false;
1347 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1362 State = ProcessZeroAllocCheck(
Call, 0, State);
1367 State = ProcessZeroAllocCheck(
Call, 0, State);
1370 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1373 case OO_Array_Delete:
1374 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1378 llvm_unreachable(
"not a new/delete operator");
1381 C.addTransition(State);
1389 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State, AF_Malloc);
1390 State = ProcessZeroAllocCheck(
Call, 0, State);
1391 C.addTransition(State);
1399 State = ProcessZeroAllocCheck(
Call, 1, State);
1400 C.addTransition(State);
1407 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1408 State = MallocMemAux(
C,
Call, TotalSize,
Init, State, AF_Malloc);
1409 State = ProcessZeroAllocCheck(
Call, 0, State);
1410 State = ProcessZeroAllocCheck(
Call, 1, State);
1411 C.addTransition(State);
1419 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1420 State = MallocMemAux(
C,
Call, TotalSize,
Init, State, AF_Malloc);
1421 State = ProcessZeroAllocCheck(
Call, 0, State);
1422 State = ProcessZeroAllocCheck(
Call, 1, State);
1423 C.addTransition(State);
1429 State = ReallocMemAux(
C,
Call,
false, State, AF_Malloc,
1431 State = ProcessZeroAllocCheck(
Call, 1, State);
1432 State = ProcessZeroAllocCheck(
Call, 2, State);
1433 C.addTransition(State);
1436void MallocChecker::checkOwnershipAttr(
const CallEvent &
Call,
1439 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1445 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1446 ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1451 switch (I->getOwnKind()) {
1452 case OwnershipAttr::Returns:
1453 State = MallocMemReturnsAttr(
C,
Call, I, State);
1455 case OwnershipAttr::Takes:
1456 case OwnershipAttr::Holds:
1457 State = FreeMemAttr(
C,
Call, I, State);
1462 C.addTransition(State);
1469 if (!
Call.getOriginExpr())
1474 if (
const CheckFn *Callback = FreeingMemFnMap.lookup(
Call)) {
1475 (*Callback)(
this,
Call,
C);
1479 if (
const CheckFn *Callback = AllocatingMemFnMap.lookup(
Call)) {
1480 (*Callback)(
this,
Call,
C);
1484 if (
const CheckFn *Callback = ReallocatingMemFnMap.lookup(
Call)) {
1485 (*Callback)(
this,
Call,
C);
1490 checkCXXNewOrCXXDelete(
Call,
C);
1494 checkOwnershipAttr(
Call,
C);
1500 std::optional<SVal> RetVal) {
1505 RetVal =
Call.getReturnValue();
1507 const Expr *Arg =
nullptr;
1509 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1510 Arg = CE->getArg(IndexOfSizeArg);
1512 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1513 if (
NE->isArray()) {
1514 Arg = *
NE->getArraySize();
1519 llvm_unreachable(
"not a CallExpr or CXXNewExpr");
1531 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1535 std::tie(TrueState, FalseState) =
1536 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal, Zero));
1538 if (TrueState && !FalseState) {
1539 SymbolRef Sym = RetVal->getAsLocSymbol();
1543 const RefState *RS = State->get<RegionState>(Sym);
1545 if (RS->isAllocated())
1546 return TrueState->set<RegionState>(Sym,
1547 RefState::getAllocatedOfSizeZero(RS));
1555 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1566 while (!PointeeType.isNull()) {
1567 Result = PointeeType;
1568 PointeeType = PointeeType->getPointeeType();
1581 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1587 for (
const auto *CtorParam : CtorD->
parameters()) {
1590 if (CtorParamPointeeT.
isNull())
1605 AllocationFamily Family)
const {
1610 const ParentMap &PM =
C.getLocationContext()->getParentMap();
1626 State = ProcessZeroAllocCheck(
Call, 0, State, Target);
1632 if (!
C.wasInlined) {
1635 (
Call.getOriginExpr()->isArray() ? AF_CXXNewArray : AF_CXXNew));
1636 C.addTransition(State);
1646 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1647 return FirstSlot ==
"dataWithBytesNoCopy" ||
1648 FirstSlot ==
"initWithBytesNoCopy" ||
1649 FirstSlot ==
"initWithCharactersNoCopy";
1656 for (
unsigned i = 1; i < S.getNumArgs(); ++i)
1657 if (S.getNameForSlot(i).equals(
"freeWhenDone"))
1658 return !
Call.getArgSVal(i).isZeroConstant();
1660 return std::nullopt;
1675 if (
Call.hasNonZeroCallbackArg())
1678 bool IsKnownToBeAllocatedMemory;
1680 FreeMemAux(
C,
Call.getArgExpr(0),
Call,
C.getState(),
1681 true, IsKnownToBeAllocatedMemory, AF_Malloc,
1684 C.addTransition(State);
1689 const OwnershipAttr *Att,
1694 if (Att->getModule()->getName() !=
"malloc")
1697 if (!Att->args().empty()) {
1698 return MallocMemAux(
C,
Call,
1699 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1709 AllocationFamily Family) {
1714 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
1720 AllocationFamily Family) {
1724 const Expr *CE =
Call.getOriginExpr();
1733 unsigned Count =
C.blockCount();
1740 State = State->BindExpr(CE,
C.getLocationContext(), RetVal);
1743 State = State->bindDefaultInitial(RetVal,
Init, LCtx);
1758 AllocationFamily Family,
1759 std::optional<SVal> RetVal) {
1765 RetVal =
C.getSVal(E);
1768 if (!RetVal->getAs<
Loc>())
1771 SymbolRef Sym = RetVal->getAsLocSymbol();
1777 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
1782 const OwnershipAttr *Att,
1787 if (Att->getModule()->getName() !=
"malloc")
1790 bool IsKnownToBeAllocated =
false;
1792 for (
const auto &Arg : Att->args()) {
1794 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
1795 Att->getOwnKind() == OwnershipAttr::Holds,
1796 IsKnownToBeAllocated, AF_Malloc);
1806 bool Hold,
bool &IsKnownToBeAllocated,
1807 AllocationFamily Family,
1808 bool ReturnsNullOnFailure)
const {
1812 if (
Call.getNumArgs() < (Num + 1))
1815 return FreeMemAux(
C,
Call.getArgExpr(Num),
Call, State, Hold,
1816 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
1823 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
1825 assert(*Ret &&
"We should not store the null return symbol");
1828 RetStatusSymbol = *Ret;
1835 if (
const CallExpr *CE = dyn_cast<CallExpr>(E)) {
1848 if (Msg->isInstanceMessage())
1852 Msg->getSelector().
print(os);
1856 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
1876 case AF_Malloc: os <<
"malloc()";
return;
1877 case AF_CXXNew: os <<
"'new'";
return;
1878 case AF_CXXNewArray: os <<
"'new[]'";
return;
1879 case AF_IfNameIndex: os <<
"'if_nameindex()'";
return;
1880 case AF_InnerBuffer: os <<
"container-specific allocator";
return;
1882 case AF_None: llvm_unreachable(
"not a deallocation expression");
1888 case AF_Malloc: os <<
"free()";
return;
1889 case AF_CXXNew: os <<
"'delete'";
return;
1890 case AF_CXXNewArray: os <<
"'delete[]'";
return;
1891 case AF_IfNameIndex: os <<
"'if_freenameindex()'";
return;
1892 case AF_InnerBuffer: os <<
"container-specific deallocator";
return;
1894 case AF_None: llvm_unreachable(
"suspicious argument");
1901 AllocationFamily Family,
bool ReturnsNullOnFailure)
const {
1906 SVal ArgVal =
C.getSVal(ArgExpr);
1907 if (!isa<DefinedOrUnknownSVal>(ArgVal))
1912 if (!isa<Loc>(location))
1917 std::tie(notNullState, nullState) = State->assume(location);
1918 if (nullState && !notNullState)
1927 const Expr *ParentExpr =
Call.getOriginExpr();
1946 if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
1947 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
1955 if (isa<BlockDataRegion>(R)) {
1956 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
1965 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
1971 if (isa<AllocaRegion>(R))
1974 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
1987 const RefState *RsBase = State->get<RegionState>(SymBase);
1988 SymbolRef PreviousRetStatusSymbol =
nullptr;
1990 IsKnownToBeAllocated =
1991 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
1996 if (RsBase->getAllocationFamily() == AF_Alloca) {
2002 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2004 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2005 SymBase, PreviousRetStatusSymbol);
2010 }
else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2011 RsBase->isEscaped()) {
2014 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2015 if (!DeallocMatchesAlloc) {
2017 RsBase, SymBase, Hold);
2024 if (Offset.isValid() &&
2025 !Offset.hasSymbolicOffset() &&
2026 Offset.getOffset() != 0) {
2027 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2036 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2042 State = State->remove<FreeReturnValue>(SymBase);
2046 if (ReturnsNullOnFailure) {
2047 SVal RetVal =
C.getSVal(ParentExpr);
2049 if (RetStatusSymbol) {
2050 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2051 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2059 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2063 return State->set<RegionState>(SymBase,
2064 RefState::getRelinquished(Family,
2067 return State->set<RegionState>(SymBase,
2068 RefState::getReleased(Family, ParentExpr));
2071std::optional<MallocChecker::CheckKind>
2072MallocChecker::getCheckIfTracked(AllocationFamily Family,
2073 bool IsALeakCheck)
const {
2077 case AF_IfNameIndex: {
2078 if (ChecksEnabled[CK_MallocChecker])
2079 return CK_MallocChecker;
2080 return std::nullopt;
2083 case AF_CXXNewArray: {
2085 if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2086 return CK_NewDeleteLeaksChecker;
2089 if (ChecksEnabled[CK_NewDeleteChecker])
2090 return CK_NewDeleteChecker;
2092 return std::nullopt;
2094 case AF_InnerBuffer: {
2095 if (ChecksEnabled[CK_InnerPointerChecker])
2096 return CK_InnerPointerChecker;
2097 return std::nullopt;
2100 llvm_unreachable(
"no family");
2103 llvm_unreachable(
"unhandled family");
2106std::optional<MallocChecker::CheckKind>
2108 bool IsALeakCheck)
const {
2109 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2110 return CK_MallocChecker;
2112 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2114 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2117bool MallocChecker::SummarizeValue(raw_ostream &os,
SVal V) {
2118 if (std::optional<nonloc::ConcreteInt> IntVal =
2120 os <<
"an integer (" << IntVal->getValue() <<
")";
2121 else if (std::optional<loc::ConcreteInt> ConstAddr =
2123 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2125 os <<
"the address of the label '" <<
Label->getLabel()->getName() <<
"'";
2132bool MallocChecker::SummarizeRegion(raw_ostream &os,
2135 case MemRegion::FunctionCodeRegionKind: {
2136 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2138 os <<
"the address of the function '" << *FD <<
'\'';
2140 os <<
"the address of a function";
2143 case MemRegion::BlockCodeRegionKind:
2146 case MemRegion::BlockDataRegionKind:
2153 if (isa<StackLocalsSpaceRegion>(MS)) {
2154 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2162 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2164 os <<
"the address of a local stack variable";
2168 if (isa<StackArgumentsSpaceRegion>(MS)) {
2169 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2177 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2179 os <<
"the address of a parameter";
2183 if (isa<GlobalsSpaceRegion>(MS)) {
2184 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2193 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2195 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2197 os <<
"the address of a global variable";
2208 const Expr *DeallocExpr,
2209 AllocationFamily Family)
const {
2211 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2216 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2221 if (!BT_BadFree[*CheckKind])
2222 BT_BadFree[*CheckKind].reset(
new BugType(
2226 llvm::raw_svector_ostream os(buf);
2229 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2230 MR = ER->getSuperRegion();
2232 os <<
"Argument to ";
2234 os <<
"deallocator";
2237 bool Summarized = MR ? SummarizeRegion(os, MR)
2238 : SummarizeValue(os, ArgVal);
2240 os <<
", which is not memory allocated by ";
2242 os <<
"not memory allocated by ";
2246 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2248 R->markInteresting(MR);
2250 C.emitReport(std::move(R));
2257 std::optional<MallocChecker::CheckKind> CheckKind;
2259 if (ChecksEnabled[CK_MallocChecker])
2260 CheckKind = CK_MallocChecker;
2261 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2262 CheckKind = CK_MismatchedDeallocatorChecker;
2269 if (!BT_FreeAlloca[*CheckKind])
2270 BT_FreeAlloca[*CheckKind].reset(
new BugType(
2273 auto R = std::make_unique<PathSensitiveBugReport>(
2274 *BT_FreeAlloca[*CheckKind],
2275 "Memory allocated by alloca() should not be deallocated", N);
2278 C.emitReport(std::move(R));
2284 const Expr *DeallocExpr,
2286 bool OwnershipTransferred)
const {
2288 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2294 if (!BT_MismatchedDealloc)
2295 BT_MismatchedDealloc.reset(
2296 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2300 llvm::raw_svector_ostream os(buf);
2302 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2304 llvm::raw_svector_ostream AllocOs(AllocBuf);
2306 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2308 if (OwnershipTransferred) {
2310 os << DeallocOs.str() <<
" cannot";
2314 os <<
" take ownership of memory";
2317 os <<
" allocated by " << AllocOs.str();
2321 os <<
" allocated by " << AllocOs.str();
2323 os <<
" should be deallocated by ";
2327 os <<
", not " << DeallocOs.str();
2330 auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2332 R->markInteresting(Sym);
2334 R->addVisitor<MallocBugVisitor>(Sym);
2335 C.emitReport(std::move(R));
2341 AllocationFamily Family,
2342 const Expr *AllocExpr)
const {
2344 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2349 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2357 if (!BT_OffsetFree[*CheckKind])
2358 BT_OffsetFree[*CheckKind].reset(
new BugType(
2362 llvm::raw_svector_ostream os(buf);
2364 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2367 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2370 assert((Offset.isValid() &&
2371 !Offset.hasSymbolicOffset() &&
2372 Offset.getOffset() != 0) &&
2373 "Only symbols with a valid offset can have offset free errors");
2375 int offsetBytes = Offset.getOffset() /
C.getASTContext().getCharWidth();
2377 os <<
"Argument to ";
2379 os <<
"deallocator";
2380 os <<
" is offset by "
2383 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2384 <<
" from the start of ";
2386 os <<
"memory allocated by " << AllocNameOs.str();
2388 os <<
"allocated memory";
2390 auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2394 C.emitReport(std::move(R));
2400 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2401 !ChecksEnabled[CK_InnerPointerChecker]) {
2406 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2411 if (!BT_UseFree[*CheckKind])
2412 BT_UseFree[*CheckKind].reset(
new BugType(
2415 AllocationFamily AF =
2416 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2418 auto R = std::make_unique<PathSensitiveBugReport>(
2419 *BT_UseFree[*CheckKind],
2420 AF == AF_InnerBuffer
2421 ?
"Inner pointer of container used after re/deallocation"
2422 :
"Use of memory after it is freed",
2425 R->markInteresting(Sym);
2427 R->addVisitor<MallocBugVisitor>(Sym);
2429 if (AF == AF_InnerBuffer)
2432 C.emitReport(std::move(R));
2440 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2445 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2450 if (!BT_DoubleFree[*CheckKind])
2451 BT_DoubleFree[*CheckKind].reset(
new BugType(
2454 auto R = std::make_unique<PathSensitiveBugReport>(
2455 *BT_DoubleFree[*CheckKind],
2456 (Released ?
"Attempt to free released memory"
2457 :
"Attempt to free non-owned memory"),
2460 R->markInteresting(Sym);
2462 R->markInteresting(PrevSym);
2463 R->addVisitor<MallocBugVisitor>(Sym);
2464 C.emitReport(std::move(R));
2470 if (!ChecksEnabled[CK_NewDeleteChecker]) {
2475 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2480 if (!BT_DoubleDelete)
2481 BT_DoubleDelete.reset(
new BugType(CheckNames[CK_NewDeleteChecker],
2485 auto R = std::make_unique<PathSensitiveBugReport>(
2486 *BT_DoubleDelete,
"Attempt to delete released memory", N);
2488 R->markInteresting(Sym);
2489 R->addVisitor<MallocBugVisitor>(Sym);
2490 C.emitReport(std::move(R));
2497 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2502 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2508 if (!BT_UseZerroAllocated[*CheckKind])
2509 BT_UseZerroAllocated[*CheckKind].reset(
2510 new BugType(CheckNames[*CheckKind],
"Use of zero allocated",
2513 auto R = std::make_unique<PathSensitiveBugReport>(
2514 *BT_UseZerroAllocated[*CheckKind],
2515 "Use of memory allocated with size zero", N);
2519 R->markInteresting(Sym);
2520 R->addVisitor<MallocBugVisitor>(Sym);
2522 C.emitReport(std::move(R));
2528 const Expr *FreeExpr,
2529 AllocationFamily Family)
const {
2530 if (!ChecksEnabled[CK_MallocChecker]) {
2535 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2540 if (!BT_BadFree[*CheckKind])
2541 BT_BadFree[*CheckKind].reset(
new BugType(
2545 llvm::raw_svector_ostream Os(Buf);
2548 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2549 MR = ER->getSuperRegion();
2551 Os <<
"Argument to ";
2553 Os <<
"deallocator";
2555 Os <<
" is a function pointer";
2557 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2559 R->markInteresting(MR);
2561 C.emitReport(std::move(R));
2568 AllocationFamily Family,
bool SuffixWithN)
const {
2572 const CallExpr *CE = cast<CallExpr>(
Call.getOriginExpr());
2580 SVal Arg0Val =
C.getSVal(arg0Expr);
2581 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2588 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2594 SVal TotalSize =
C.getSVal(Arg1);
2596 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2597 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2603 svalBuilder.makeIntValWithWidth(
2604 svalBuilder.getContext().getSizeType(), 0));
2607 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2609 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2612 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2613 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2617 if (PrtIsNull && !SizeIsZero) {
2623 if (PrtIsNull && SizeIsZero)
2628 bool IsKnownToBeAllocated =
false;
2637 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2642 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2649 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2650 if (ShouldFreeOnFail)
2651 Kind = OAR_FreeOnFailure;
2652 else if (!IsKnownToBeAllocated)
2653 Kind = OAR_DoNotTrackAfterFailure;
2657 SVal RetVal =
C.getSVal(CE);
2659 assert(FromPtr && ToPtr &&
2660 "By this point, FreeMemAux and MallocMemAux should have checked "
2661 "whether the argument or the return value is symbolic!");
2665 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2666 ReallocPair(FromPtr, Kind));
2668 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2669 return stateRealloc;
2680 if (
Call.getNumArgs() < 2)
2686 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2688 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State, AF_Malloc);
2691MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2698 const MemRegion *ReferenceRegion =
nullptr;
2702 if (!State->get<RegionState>(Sym))
2707 if (!ReferenceRegion) {
2708 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
2709 SVal Val = State->getSVal(MR);
2715 ReferenceRegion = MR;
2723 if (NContext == LeakContext ||
2729 return LeakInfo(AllocNode, ReferenceRegion);
2735 if (!ChecksEnabled[CK_MallocChecker] &&
2736 !ChecksEnabled[CK_NewDeleteLeaksChecker])
2739 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2740 assert(RS &&
"cannot leak an untracked symbol");
2741 AllocationFamily Family = RS->getAllocationFamily();
2743 if (Family == AF_Alloca)
2746 std::optional<MallocChecker::CheckKind> CheckKind =
2747 getCheckIfTracked(Family,
true);
2753 if (!BT_Leak[*CheckKind]) {
2759 BT_Leak[*CheckKind].reset(
new BugType(CheckNames[*CheckKind],
"Memory leak",
2770 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
2775 C.getSourceManager(),
2779 llvm::raw_svector_ostream os(buf);
2781 os <<
"Potential leak of memory pointed to by ";
2784 os <<
"Potential memory leak";
2787 auto R = std::make_unique<PathSensitiveBugReport>(
2788 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
2790 R->markInteresting(Sym);
2791 R->addVisitor<MallocBugVisitor>(Sym,
true);
2792 if (ShouldRegisterNoOwnershipChangeVisitor)
2793 R->addVisitor<NoOwnershipChangeVisitor>(Sym,
this);
2794 C.emitReport(std::move(R));
2797void MallocChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
2801 RegionStateTy OldRS = state->get<RegionState>();
2802 RegionStateTy::Factory &F = state->get_context<RegionState>();
2804 RegionStateTy RS = OldRS;
2806 for (
auto [Sym, State] : RS) {
2807 if (SymReaper.
isDead(Sym)) {
2808 if (State.isAllocated() || State.isAllocatedOfSizeZero())
2809 Errors.push_back(Sym);
2811 RS = F.remove(RS, Sym);
2817 assert(state->get<ReallocPairs>() ==
2818 C.getState()->get<ReallocPairs>());
2819 assert(state->get<FreeReturnValue>() ==
2820 C.getState()->get<FreeReturnValue>());
2825 ReallocPairsTy RP = state->get<ReallocPairs>();
2826 for (
auto [Sym, ReallocPair] : RP) {
2827 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
2828 state = state->remove<ReallocPairs>(Sym);
2833 FreeReturnValueTy FR = state->get<FreeReturnValue>();
2834 for (
auto [Sym, RetSym] : FR) {
2835 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
2836 state = state->remove<FreeReturnValue>(Sym);
2842 if (!Errors.empty()) {
2844 N =
C.generateNonFatalErrorNode(
C.getState(), &Tag);
2847 HandleLeak(Sym, N,
C);
2852 C.addTransition(state->set<RegionState>(RS), N);
2858 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
2861 if (!ChecksEnabled[CK_NewDeleteChecker])
2869 bool IsKnownToBeAllocated;
2871 false, IsKnownToBeAllocated,
2872 (DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
2874 C.addTransition(State);
2878 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
2879 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
2880 if (!Sym || checkDoubleDelete(Sym,
C))
2890 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(
Call))
2896 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
2897 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
2902 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
2904 if (isa<Loc>(ArgSVal)) {
2908 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
2914void MallocChecker::checkPreStmt(
const ReturnStmt *S,
2916 checkEscapeOnReturn(S,
C);
2922void MallocChecker::checkEndFunction(
const ReturnStmt *S,
2924 checkEscapeOnReturn(S,
C);
2927void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
2932 const Expr *E = S->getRetValue();
2938 SVal RetVal =
C.getSVal(E);
2945 if (isa<FieldRegion, ElementRegion>(MR))
2948 Sym = BMR->getSymbol();
2952 checkUseAfterFree(Sym,
C, E);
2958void MallocChecker::checkPostStmt(
const BlockExpr *BE,
2968 cast<BlockDataRegion>(
C.getSVal(BE).getAsRegion());
2971 if (ReferencedVars.empty())
2978 for (
const auto &Var : ReferencedVars) {
2979 const VarRegion *VR = Var.getCapturedRegion();
2983 Regions.push_back(VR);
2987 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
2988 C.addTransition(state);
2993 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2994 return (RS && RS->isReleased());
2997bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
2999 if (
Call.getNumArgs() == 0)
3002 StringRef FunctionStr =
"";
3003 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3005 if (Body->getBeginLoc().isValid())
3009 C.getSourceManager(),
C.getLangOpts());
3012 if (!FunctionStr.contains(
"__isl_"))
3017 for (
const Expr *Arg : cast<CallExpr>(
Call.getOriginExpr())->arguments())
3018 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3019 if (
const RefState *RS = State->get<RegionState>(Sym))
3020 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3022 C.addTransition(State);
3027 const Stmt *S)
const {
3030 HandleUseAfterFree(
C, S->getSourceRange(), Sym);
3038 const Stmt *S)
const {
3041 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3042 if (RS->isAllocatedOfSizeZero())
3043 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3045 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3046 HandleUseZeroAlloc(
C, S->getSourceRange(), Sym);
3053 HandleDoubleDelete(
C, Sym);
3060void MallocChecker::checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
3064 checkUseAfterFree(Sym,
C, S);
3065 checkUseZeroAllocated(Sym,
C, S);
3073 bool Assumption)
const {
3074 RegionStateTy RS = state->get<RegionState>();
3075 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3080 state = state->remove<RegionState>(Sym);
3085 ReallocPairsTy RP = state->get<ReallocPairs>();
3086 for (
auto [Sym, ReallocPair] : RP) {
3093 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3094 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3095 if (RS->isReleased()) {
3096 switch (ReallocPair.Kind) {
3097 case OAR_ToBeFreedAfterFailure:
3098 state = state->set<RegionState>(ReallocSym,
3099 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3101 case OAR_DoNotTrackAfterFailure:
3102 state = state->remove<RegionState>(ReallocSym);
3105 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3109 state = state->remove<ReallocPairs>(Sym);
3115bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3120 EscapingSymbol =
nullptr;
3126 if (!isa<SimpleFunctionCall, ObjCMethodCall>(
Call))
3133 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3146 return *FreeWhenDone;
3152 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3153 if (FirstSlot.endswith(
"NoCopy"))
3160 if (FirstSlot.startswith(
"addPointer") ||
3161 FirstSlot.startswith(
"insertPointer") ||
3162 FirstSlot.startswith(
"replacePointer") ||
3163 FirstSlot.equals(
"valueWithPointer")) {
3170 if (Msg->getMethodFamily() ==
OMF_init) {
3171 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3187 if (isMemCall(*
Call))
3191 if (!
Call->isInSystemHeader())
3198 StringRef FName = II->
getName();
3202 if (FName.endswith(
"NoCopy")) {
3206 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3207 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3208 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3209 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3210 if (DeallocatorName ==
"kCFAllocatorNull")
3221 if (FName ==
"funopen")
3222 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3228 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3229 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3230 if (
Call->getNumArgs() >= 1) {
3231 const Expr *ArgE =
Call->getArgExpr(0)->IgnoreParenCasts();
3232 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3233 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3234 if (D->getCanonicalDecl()->getName().contains(
"std"))
3244 if (FName ==
"CGBitmapContextCreate" ||
3245 FName ==
"CGBitmapContextCreateWithData" ||
3246 FName ==
"CVPixelBufferCreateWithBytes" ||
3247 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3248 FName ==
"OSAtomicEnqueue") {
3252 if (FName ==
"postEvent" &&
3257 if (FName ==
"connectImpl" &&
3262 if (FName ==
"singleShotImpl" &&
3271 if (
Call->argumentsMayEscape())
3283 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3292 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3297 return (RS->getAllocationFamily() == AF_CXXNewArray ||
3298 RS->getAllocationFamily() == AF_CXXNew);
3304 bool IsConstPointerEscape)
const {
3309 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3316 if (EscapingSymbol && EscapingSymbol != sym)
3319 if (
const RefState *RS = State->get<RegionState>(sym))
3320 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3322 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3328 SVal ArgVal)
const {
3329 if (!KernelZeroSizePtrValue)
3330 KernelZeroSizePtrValue =
3333 const llvm::APSInt *ArgValKnown =
3334 C.getSValBuilder().getKnownValue(State, ArgVal);
3335 return ArgValKnown && *KernelZeroSizePtrValue &&
3336 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3341 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3342 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3344 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3346 if (!currMap.lookup(sym))
3356 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3357 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3358 N.contains_insensitive(
"intrusive") ||
3359 N.contains_insensitive(
"shared")) {
3373 const RefState *RSCurr = state->get<RegionState>(Sym);
3374 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3379 if (!S && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer))
3391 if (ReleaseDestructorLC) {
3392 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3394 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3395 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3396 if (ReleaseDestructorLC == CurrentLC ||
3397 ReleaseDestructorLC->
isParentOf(CurrentLC)) {
3409 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3411 llvm::raw_svector_ostream OS(Buf);
3414 if (isAllocated(RSCurr, RSPrev, S)) {
3415 Msg =
"Memory is allocated";
3416 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3417 Sym,
"Returned allocated memory");
3419 const auto Family = RSCurr->getAllocationFamily();
3424 case AF_CXXNewArray:
3425 case AF_IfNameIndex:
3426 Msg =
"Memory is released";
3427 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3428 Sym,
"Returning; memory was released");
3430 case AF_InnerBuffer: {
3433 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
3435 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
3438 OS <<
"deallocated by call to destructor";
3439 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3440 Sym,
"Returning; inner buffer was deallocated");
3442 OS <<
"reallocated by call to '";
3443 const Stmt *S = RSCurr->getStmt();
3444 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3445 OS << MemCallE->getMethodDecl()->getDeclName();
3446 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3447 OS << OpCallE->getDirectCallee()->getDeclName();
3448 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
3451 CEMgr.getSimpleCall(CallE, state, CurrentLC, {
nullptr, 0});
3452 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
3453 OS << D->getDeclName();
3458 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3459 Sym,
"Returning; inner buffer was reallocated");
3465 llvm_unreachable(
"Unhandled allocation family!");
3471 bool FoundAnyDestructor =
false;
3473 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
3479 }
else if (!FoundAnyDestructor) {
3480 assert(!ReleaseDestructorLC &&
3481 "There can be only one release point!");
3493 FoundAnyDestructor =
true;
3497 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
3498 Msg =
"Memory ownership is transferred";
3499 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
3500 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3501 Mode = ReallocationFailed;
3502 Msg =
"Reallocation failed";
3503 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3504 Sym,
"Reallocation failed");
3508 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3509 "We only support one failed realloc at a time.");
3511 FailedReallocSymbol = sym;
3516 }
else if (Mode == ReallocationFailed) {
3517 assert(FailedReallocSymbol &&
"No symbol to look for.");
3520 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3522 Msg =
"Attempt to reallocate memory";
3523 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3524 Sym,
"Returned reallocated memory");
3525 FailedReallocSymbol =
nullptr;
3540 assert(RSCurr->getAllocationFamily() == AF_InnerBuffer);
3551 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
3556void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
3557 const char *NL,
const char *Sep)
const {
3559 RegionStateTy RS = State->get<RegionState>();
3561 if (!RS.isEmpty()) {
3562 Out << Sep <<
"MallocChecker :" << NL;
3563 for (
auto [Sym,
Data] : RS) {
3564 const RefState *RefS = State->get<RegionState>(Sym);
3565 AllocationFamily Family = RefS->getAllocationFamily();
3566 std::optional<MallocChecker::CheckKind> CheckKind =
3567 getCheckIfTracked(Family);
3569 CheckKind = getCheckIfTracked(Family,
true);
3575 Out <<
" (" << CheckNames[*CheckKind].getName() <<
")";
3583namespace allocation_state {
3587 AllocationFamily Family = AF_InnerBuffer;
3588 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3598 MallocChecker *checker = mgr.
getChecker<MallocChecker>();
3599 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] =
true;
3600 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3606 checker->ShouldIncludeOwnershipAnnotatedFunctions =
3608 checker->ShouldRegisterNoOwnershipChangeVisitor =
3610 checker,
"AddNoOwnershipChangeNotes");
3613bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
3617#define REGISTER_CHECKER(name) \
3618 void ento::register##name(CheckerManager &mgr) { \
3619 MallocChecker *checker = mgr.getChecker<MallocChecker>(); \
3620 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
3621 checker->CheckNames[MallocChecker::CK_##name] = \
3622 mgr.getCurrentCheckerName(); \
3625 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
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.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
#define REGISTER_CHECKER(name)
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 bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
static bool isGRealloc(const CallEvent &Call)
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 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 isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool isStandardNewDelete(const FunctionDecl *FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
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)
__device__ __2f16 float __ockl_bool s
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
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 point when we begin processing an inlined call.
const Stmt * getCallExpr() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
static CharSourceRange getTokenRange(SourceRange R)
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
SourceLocation getLocation() const
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
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.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
This represents a decl that may have a name.
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
An expression that sends a message to the given Objective-C object or class.
bool isConsumedExpr(Expr *E) const
Represents a program point just after an implicit call event.
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.
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Smart pointer class that efficiently represents Objective-C method names.
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.
A trivial tuple used to represent a source range.
It represents a stack frame of the call stack (based on CallEvent).
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isFunctionPointerType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Maps string IDs to AST nodes matched by parts of a matcher.
Represents a call to any sort of function that might have a FunctionDecl.
BlockDataRegion - A region that represents a block instance.
llvm::iterator_range< referenced_vars_iterator > referenced_vars() const
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.
virtual void Profile(llvm::FoldingSetNodeID &ID) const =0
virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR)=0
Return a diagnostic piece which should be associated with the given node.
virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR)
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
Represents the memory allocation call in a C++ new-expression.
Represents a call to a C++ constructor.
Represents a non-static C++ member function call, no matter how it is written.
An immutable map from CallDescriptions to arbitrary data.
Represents an abstract call to a function or method along a particular path.
virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const
See CheckerManager::runCheckersForPrintState.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
CheckerNameRef getCurrentCheckerName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
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...
ElementRegion is used to represent both array elements and casts.
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.
const LocationContext * getLocationContext() const
std::optional< T > getLocationAs() const &
ExplodedNode * getFirstPred()
static bool isLocType(QualType T)
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
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.
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
Put a diagnostic on return statement (or on } in its absence) of all inlined functions for which some...
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()
A Range represents the closed range [from, to].
Represent a region's offset within the top level base region.
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
ASTContext & getContext()
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...
DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Conjure a symbol representing heap allocated memory region.
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.
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.
Constructs a Stack hint for the given symbol.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
virtual void dumpToStream(raw_ostream &os) const
virtual QualType getType() const =0
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
virtual bool VisitSymbol(SymbolRef sym)=0
A visitor method invoked by ProgramStateManager::scanReachableSymbols.
SymbolicRegion - A special, "non-concrete" region.
SymbolRef getSymbol() const
It might return null.
TypedRegion - An abstract class representing regions that are typed.
const VarDecl * getDecl() const override=0
const StackFrameContext * getStackFrame() const
It might return null.
Value representing integer constant.
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.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
const char *const MemoryError
@ CDF_MaybeBuiltin
Describes a C standard function that is sometimes implemented as a macro that expands to a compiler b...
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent, SValBuilder &SVB)
Set the dynamic extent Extent of the region MR.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool NE(InterpState &S, CodePtr OpPC)
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
bool Zero(InterpState &S, CodePtr OpPC)
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.