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;
391 bool ShouldFreeOnFail)
const;
393 using CheckFn = std::function<void(
const MallocChecker *,
399 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetdelim},
400 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetdelim},
404 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
405 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
406 &MallocChecker::checkIfFreeNameIndex},
407 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
408 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
414 friend class NoOwnershipChangeVisitor;
417 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
418 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
422 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
423 &MallocChecker::checkAlloca},
424 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
425 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
426 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
427 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
428 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
429 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
430 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
431 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
432 {{CDM::CLibrary, {
"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
433 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
434 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
435 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
436 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
437 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
438 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
439 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
440 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
441 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
442 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
443 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
447 {{CDM::CLibrary, {
"realloc"}, 2},
448 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
449 {{CDM::CLibrary, {
"reallocf"}, 2},
450 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
true)},
451 {{CDM::CLibrary, {
"g_realloc"}, 2},
452 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
453 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
454 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
455 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
456 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
460 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetdelim},
461 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::checkGetdelim},
467 mutable std::optional<uint64_t> KernelZeroFlagVal;
469 using KernelZeroSizePtrValueTy = std::optional<int>;
474 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
480 AllocationFamily Family)
const;
491 ProcessZeroAllocCheck(
const CallEvent &
Call,
const unsigned IndexOfSizeArg,
493 std::optional<SVal> RetVal = std::nullopt);
543 [[nodiscard]] std::optional<ProgramStateRef>
566 const OwnershipAttr *Att,
590 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
591 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
617 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
618 std::optional<SVal> ArgValOpt = {})
const;
636 bool SuffixWithN =
false)
const;
645 const Expr *BlockBytes);
657 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
666 const Stmt *S)
const;
681 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
690 bool IsConstPointerEscape)
const;
699 std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
700 bool IsALeakCheck =
false)
const;
703 bool IsALeakCheck =
false)
const;
705 static bool SummarizeValue(raw_ostream &os,
SVal V);
706 static bool SummarizeRegion(raw_ostream &os,
const MemRegion *MR);
709 const Expr *DeallocExpr,
710 AllocationFamily Family)
const;
716 const Expr *DeallocExpr,
const RefState *RS,
717 SymbolRef Sym,
bool OwnershipTransferred)
const;
720 const Expr *DeallocExpr, AllocationFamily Family,
721 const Expr *AllocExpr =
nullptr)
const;
735 const Expr *FreeExpr,
736 AllocationFamily Family)
const;
769 OwnershipBindingsHandler(
SymbolRef Sym, OwnerSet &Owners)
770 : Sym(Sym), Owners(Owners) {}
775 Owners.insert(Region);
779 LLVM_DUMP_METHOD
void dump()
const { dumpToStream(llvm::errs()); }
780 LLVM_DUMP_METHOD
void dumpToStream(llvm::raw_ostream &out)
const {
781 out <<
"Owners: {\n";
784 Owner->dumpToStream(out);
796 OwnershipBindingsHandler Handler{Sym,
Ret};
797 State->getStateManager().getStoreManager().iterBindings(State->getStore(),
802 LLVM_DUMP_METHOD
static std::string
804 if (
const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>(
807 return FD->getQualifiedNameAsString();
818 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
819 if (
Checker.FreeingMemFnMap.lookupAsWritten(
Call) ||
820 Checker.ReallocatingMemFnMap.lookupAsWritten(
Call))
823 if (
const auto *
Func =
824 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
825 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
834 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
ASTContext &ACtx) {
836 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
854 if (
const auto *
Call = Match.getNodeAs<
CallExpr>(
"call"))
855 if (isFreeingCallAsWritten(*
Call))
864 bool wasModifiedInFunction(
const ExplodedNode *CallEnterN,
866 if (!doesFnIntendToHandleOwnership(
868 CallExitEndN->
getState()->getAnalysisManager().getASTContext()))
871 if (CallEnterN->
getState()->get<RegionState>(Sym) !=
872 CallExitEndN->
getState()->get<RegionState>(Sym))
875 OwnerSet CurrOwners = getOwnersAtNode(CallEnterN);
876 OwnerSet ExitOwners = getOwnersAtNode(CallExitEndN);
884 return !llvm::set_is_subset(ExitOwners, CurrOwners);
890 N->
getState()->getStateManager().getContext().getSourceManager());
891 return std::make_shared<PathDiagnosticEventPiece>(
892 L,
"Returning without deallocating memory or storing the pointer for "
893 "later deallocation");
920 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
922 if (
V.getAsSymbol() == Sym)
933 void Profile(llvm::FoldingSetNodeID &ID)
const override {
952 enum NotificationMode {
Normal, ReallocationFailed };
958 NotificationMode Mode;
970 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
971 : Sym(S), Mode(
Normal), FailedReallocSymbol(nullptr),
972 ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
974 static void *getTag() {
979 void Profile(llvm::FoldingSetNodeID &ID)
const override {
980 ID.AddPointer(getTag());
985 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
987 return (isa_and_nonnull<CallExpr, CXXNewExpr>(
Stmt) &&
989 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
991 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
996 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
999 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
1000 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(
Stmt)) ||
1001 (!
Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer));
1006 static inline bool isRelinquished(
const RefState *RSCurr,
1007 const RefState *RSPrev,
const Stmt *
Stmt) {
1009 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(
Stmt) &&
1010 (RSCurr && RSCurr->isRelinquished()) &&
1011 (!RSPrev || !RSPrev->isRelinquished()));
1018 static inline bool hasReallocFailed(
const RefState *RSCurr,
1019 const RefState *RSPrev,
1021 return ((!isa_and_nonnull<CallExpr>(
Stmt)) &&
1023 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1025 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1040 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1045 class StackHintGeneratorForReallocationFailed
1048 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1051 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1056 llvm::raw_svector_ostream os(buf);
1058 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1059 <<
" parameter failed";
1061 return std::string(os.str());
1065 return "Reallocation of returned value failed";
1084 state = state->remove<RegionState>(sym);
1095 if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete &&
1096 Kind != OO_Array_Delete)
1112 if (
Func->hasAttrs()) {
1113 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1114 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1115 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1122bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1123 if (FreeingMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1126 if (
const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl()))
1127 return isFreeingOwnershipAttrCall(
Func);
1133 if (FreeingMemFnMap.lookup(
Call) || AllocatingMemFnMap.lookup(
Call) ||
1134 ReallocatingMemFnMap.lookup(
Call))
1137 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1140 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1141 return Func &&
Func->hasAttr<OwnershipAttr>();
1144std::optional<ProgramStateRef>
1166 if (!KernelZeroFlagVal) {
1168 case llvm::Triple::FreeBSD:
1169 KernelZeroFlagVal = 0x0100;
1171 case llvm::Triple::NetBSD:
1172 KernelZeroFlagVal = 0x0002;
1174 case llvm::Triple::OpenBSD:
1175 KernelZeroFlagVal = 0x0008;
1177 case llvm::Triple::Linux:
1179 KernelZeroFlagVal = 0x8000;
1187 return std::nullopt;
1194 if (
Call.getNumArgs() < 2)
1195 return std::nullopt;
1197 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1198 const SVal V =
C.getSVal(FlagsEx);
1199 if (!isa<NonLoc>(
V)) {
1202 return std::nullopt;
1206 NonLoc ZeroFlag =
C.getSValBuilder()
1207 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1209 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1213 return std::nullopt;
1218 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1221 if (TrueState && !FalseState) {
1222 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1223 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1227 return std::nullopt;
1231 const Expr *BlockBytes) {
1233 SVal BlocksVal =
C.getSVal(Blocks);
1234 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1236 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1246 State = ProcessZeroAllocCheck(
Call, 0, State);
1247 C.addTransition(State);
1253 std::optional<ProgramStateRef> MaybeState =
1254 performKernelMalloc(
Call,
C, State);
1256 State = *MaybeState;
1260 C.addTransition(State);
1286 bool ShouldFreeOnFail)
const {
1296 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State, AF_Malloc);
1297 State = ProcessZeroAllocCheck(
Call, 1, State);
1298 C.addTransition(State);
1304 State = CallocMem(
C,
Call, State);
1305 State = ProcessZeroAllocCheck(
Call, 0, State);
1306 State = ProcessZeroAllocCheck(
Call, 1, State);
1307 C.addTransition(State);
1312 bool IsKnownToBeAllocatedMemory =
false;
1313 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1315 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1317 C.addTransition(State);
1325 State = ProcessZeroAllocCheck(
Call, 0, State);
1326 C.addTransition(State);
1332 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1337 C.addTransition(State);
1348 C.addTransition(State);
1351void MallocChecker::checkIfFreeNameIndex(
const CallEvent &
Call,
1354 bool IsKnownToBeAllocatedMemory =
false;
1355 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1357 C.addTransition(State);
1360void MallocChecker::checkCXXNewOrCXXDelete(
const CallEvent &
Call,
1363 bool IsKnownToBeAllocatedMemory =
false;
1364 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1379 State = ProcessZeroAllocCheck(
Call, 0, State);
1384 State = ProcessZeroAllocCheck(
Call, 0, State);
1387 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1390 case OO_Array_Delete:
1391 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1395 llvm_unreachable(
"not a new/delete operator");
1398 C.addTransition(State);
1406 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State, AF_Malloc);
1407 State = ProcessZeroAllocCheck(
Call, 0, State);
1408 C.addTransition(State);
1416 State = ProcessZeroAllocCheck(
Call, 1, State);
1417 C.addTransition(State);
1424 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1425 State = MallocMemAux(
C,
Call, TotalSize,
Init, State, AF_Malloc);
1426 State = ProcessZeroAllocCheck(
Call, 0, State);
1427 State = ProcessZeroAllocCheck(
Call, 1, State);
1428 C.addTransition(State);
1436 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1437 State = MallocMemAux(
C,
Call, TotalSize,
Init, State, AF_Malloc);
1438 State = ProcessZeroAllocCheck(
Call, 0, State);
1439 State = ProcessZeroAllocCheck(
Call, 1, State);
1440 C.addTransition(State);
1445 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1465 bool IsKnownToBeAllocated =
false;
1466 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1467 IsKnownToBeAllocated, AF_Malloc,
false, LinePtr);
1469 C.addTransition(State);
1482 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1488 const auto LinePtr =
1492 if (!LinePtr || !Size || !LinePtr->getAsRegion())
1502 State = ReallocMemAux(
C,
Call,
false, State, AF_Malloc,
1504 State = ProcessZeroAllocCheck(
Call, 1, State);
1505 State = ProcessZeroAllocCheck(
Call, 2, State);
1506 C.addTransition(State);
1509void MallocChecker::checkOwnershipAttr(
const CallEvent &
Call,
1512 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1518 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1519 ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1524 switch (I->getOwnKind()) {
1525 case OwnershipAttr::Returns:
1526 State = MallocMemReturnsAttr(
C,
Call, I, State);
1528 case OwnershipAttr::Takes:
1529 case OwnershipAttr::Holds:
1530 State = FreeMemAttr(
C,
Call, I, State);
1535 C.addTransition(State);
1542 if (!
Call.getOriginExpr())
1547 if (
const CheckFn *Callback = FreeingMemFnMap.lookup(
Call)) {
1548 (*Callback)(
this,
Call,
C);
1552 if (
const CheckFn *Callback = AllocatingMemFnMap.lookup(
Call)) {
1553 (*Callback)(
this,
Call,
C);
1557 if (
const CheckFn *Callback = ReallocatingMemFnMap.lookup(
Call)) {
1558 (*Callback)(
this,
Call,
C);
1563 checkCXXNewOrCXXDelete(
Call,
C);
1567 checkOwnershipAttr(
Call,
C);
1573 std::optional<SVal> RetVal) {
1578 RetVal =
Call.getReturnValue();
1580 const Expr *Arg =
nullptr;
1582 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1583 Arg = CE->
getArg(IndexOfSizeArg);
1585 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1586 if (
NE->isArray()) {
1587 Arg = *
NE->getArraySize();
1592 llvm_unreachable(
"not a CallExpr or CXXNewExpr");
1604 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1608 std::tie(TrueState, FalseState) =
1609 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal, Zero));
1611 if (TrueState && !FalseState) {
1612 SymbolRef Sym = RetVal->getAsLocSymbol();
1616 const RefState *RS = State->get<RegionState>(Sym);
1618 if (RS->isAllocated())
1619 return TrueState->set<RegionState>(Sym,
1620 RefState::getAllocatedOfSizeZero(RS));
1628 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1639 while (!PointeeType.isNull()) {
1640 Result = PointeeType;
1641 PointeeType = PointeeType->getPointeeType();
1654 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1660 for (
const auto *CtorParam : CtorD->
parameters()) {
1663 if (CtorParamPointeeT.
isNull())
1678 AllocationFamily Family)
const {
1683 const ParentMap &PM =
C.getLocationContext()->getParentMap();
1699 State = ProcessZeroAllocCheck(
Call, 0, State,
Target);
1705 if (!
C.wasInlined) {
1708 (
Call.getOriginExpr()->isArray() ? AF_CXXNewArray : AF_CXXNew));
1709 C.addTransition(State);
1719 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1720 return FirstSlot ==
"dataWithBytesNoCopy" ||
1721 FirstSlot ==
"initWithBytesNoCopy" ||
1722 FirstSlot ==
"initWithCharactersNoCopy";
1729 for (
unsigned i = 1; i < S.getNumArgs(); ++i)
1730 if (S.getNameForSlot(i) ==
"freeWhenDone")
1731 return !
Call.getArgSVal(i).isZeroConstant();
1733 return std::nullopt;
1748 if (
Call.hasNonZeroCallbackArg())
1751 bool IsKnownToBeAllocatedMemory;
1753 FreeMemAux(
C,
Call.getArgExpr(0),
Call,
C.getState(),
1754 true, IsKnownToBeAllocatedMemory, AF_Malloc,
1757 C.addTransition(State);
1762 const OwnershipAttr *Att,
1767 if (Att->getModule()->getName() !=
"malloc")
1770 if (!Att->args().empty()) {
1771 return MallocMemAux(
C,
Call,
1772 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1782 AllocationFamily Family) {
1787 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
1793 AllocationFamily Family) {
1797 const Expr *CE =
Call.getOriginExpr();
1806 unsigned Count =
C.blockCount();
1813 State = State->BindExpr(CE,
C.getLocationContext(), RetVal);
1816 State = State->bindDefaultInitial(RetVal,
Init, LCtx);
1835 AllocationFamily Family,
1836 std::optional<SVal> RetVal) {
1842 RetVal =
C.getSVal(E);
1845 if (!RetVal->getAs<
Loc>())
1848 SymbolRef Sym = RetVal->getAsLocSymbol();
1863 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
1868 const OwnershipAttr *Att,
1873 if (Att->getModule()->getName() !=
"malloc")
1876 bool IsKnownToBeAllocated =
false;
1878 for (
const auto &Arg : Att->args()) {
1880 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
1881 Att->getOwnKind() == OwnershipAttr::Holds,
1882 IsKnownToBeAllocated, AF_Malloc);
1892 bool Hold,
bool &IsKnownToBeAllocated,
1893 AllocationFamily Family,
1894 bool ReturnsNullOnFailure)
const {
1898 if (
Call.getNumArgs() < (Num + 1))
1901 return FreeMemAux(
C,
Call.getArgExpr(Num),
Call, State, Hold,
1902 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
1909 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
1911 assert(*Ret &&
"We should not store the null return symbol");
1914 RetStatusSymbol = *Ret;
1921 if (
const CallExpr *CE = dyn_cast<CallExpr>(E)) {
1934 if (Msg->isInstanceMessage())
1938 Msg->getSelector().
print(os);
1942 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
1962 case AF_Malloc: os <<
"malloc()";
return;
1963 case AF_CXXNew: os <<
"'new'";
return;
1964 case AF_CXXNewArray: os <<
"'new[]'";
return;
1965 case AF_IfNameIndex: os <<
"'if_nameindex()'";
return;
1966 case AF_InnerBuffer: os <<
"container-specific allocator";
return;
1968 case AF_None: llvm_unreachable(
"not a deallocation expression");
1974 case AF_Malloc: os <<
"free()";
return;
1975 case AF_CXXNew: os <<
"'delete'";
return;
1976 case AF_CXXNewArray: os <<
"'delete[]'";
return;
1977 case AF_IfNameIndex: os <<
"'if_freenameindex()'";
return;
1978 case AF_InnerBuffer: os <<
"container-specific deallocator";
return;
1980 case AF_None: llvm_unreachable(
"suspicious argument");
1987 bool Hold,
bool &IsKnownToBeAllocated,
1988 AllocationFamily Family,
bool ReturnsNullOnFailure,
1989 std::optional<SVal> ArgValOpt)
const {
1994 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
1995 if (!isa<DefinedOrUnknownSVal>(ArgVal))
2000 if (!isa<Loc>(location))
2005 std::tie(notNullState, nullState) = State->assume(location);
2006 if (nullState && !notNullState)
2015 const Expr *ParentExpr =
Call.getOriginExpr();
2034 if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2035 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2043 if (isa<BlockDataRegion>(R)) {
2044 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2053 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
2059 if (isa<AllocaRegion>(R))
2062 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2075 const RefState *RsBase = State->get<RegionState>(SymBase);
2076 SymbolRef PreviousRetStatusSymbol =
nullptr;
2078 IsKnownToBeAllocated =
2079 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2084 if (RsBase->getAllocationFamily() == AF_Alloca) {
2090 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2092 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2093 SymBase, PreviousRetStatusSymbol);
2098 }
else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2099 RsBase->isEscaped()) {
2102 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2103 if (!DeallocMatchesAlloc) {
2105 RsBase, SymBase, Hold);
2112 if (Offset.isValid() &&
2113 !Offset.hasSymbolicOffset() &&
2114 Offset.getOffset() != 0) {
2115 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2124 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2130 State = State->remove<FreeReturnValue>(SymBase);
2134 if (ReturnsNullOnFailure) {
2135 SVal RetVal =
C.getSVal(ParentExpr);
2137 if (RetStatusSymbol) {
2138 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2139 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2147 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2151 return State->set<RegionState>(SymBase,
2152 RefState::getRelinquished(Family,
2155 return State->set<RegionState>(SymBase,
2156 RefState::getReleased(Family, ParentExpr));
2159std::optional<MallocChecker::CheckKind>
2160MallocChecker::getCheckIfTracked(AllocationFamily Family,
2161 bool IsALeakCheck)
const {
2165 case AF_IfNameIndex: {
2166 if (ChecksEnabled[CK_MallocChecker])
2167 return CK_MallocChecker;
2168 return std::nullopt;
2171 case AF_CXXNewArray: {
2173 if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2174 return CK_NewDeleteLeaksChecker;
2177 if (ChecksEnabled[CK_NewDeleteChecker])
2178 return CK_NewDeleteChecker;
2180 return std::nullopt;
2182 case AF_InnerBuffer: {
2183 if (ChecksEnabled[CK_InnerPointerChecker])
2184 return CK_InnerPointerChecker;
2185 return std::nullopt;
2188 llvm_unreachable(
"no family");
2191 llvm_unreachable(
"unhandled family");
2194std::optional<MallocChecker::CheckKind>
2196 bool IsALeakCheck)
const {
2197 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2198 return CK_MallocChecker;
2200 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2202 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2205bool MallocChecker::SummarizeValue(raw_ostream &os,
SVal V) {
2206 if (std::optional<nonloc::ConcreteInt> IntVal =
2208 os <<
"an integer (" << IntVal->getValue() <<
")";
2209 else if (std::optional<loc::ConcreteInt> ConstAddr =
2211 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2213 os <<
"the address of the label '" <<
Label->getLabel()->getName() <<
"'";
2220bool MallocChecker::SummarizeRegion(raw_ostream &os,
2223 case MemRegion::FunctionCodeRegionKind: {
2224 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2226 os <<
"the address of the function '" << *FD <<
'\'';
2228 os <<
"the address of a function";
2231 case MemRegion::BlockCodeRegionKind:
2234 case MemRegion::BlockDataRegionKind:
2241 if (isa<StackLocalsSpaceRegion>(MS)) {
2242 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2250 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2252 os <<
"the address of a local stack variable";
2256 if (isa<StackArgumentsSpaceRegion>(MS)) {
2257 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2265 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2267 os <<
"the address of a parameter";
2271 if (isa<GlobalsSpaceRegion>(MS)) {
2272 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2281 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2283 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2285 os <<
"the address of a global variable";
2296 const Expr *DeallocExpr,
2297 AllocationFamily Family)
const {
2299 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2304 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2309 if (!BT_BadFree[*CheckKind])
2310 BT_BadFree[*CheckKind].reset(
new BugType(
2314 llvm::raw_svector_ostream os(buf);
2317 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2318 MR = ER->getSuperRegion();
2320 os <<
"Argument to ";
2322 os <<
"deallocator";
2325 bool Summarized = MR ? SummarizeRegion(os, MR)
2326 : SummarizeValue(os, ArgVal);
2328 os <<
", which is not memory allocated by ";
2330 os <<
"not memory allocated by ";
2334 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2336 R->markInteresting(MR);
2338 C.emitReport(std::move(R));
2345 std::optional<MallocChecker::CheckKind> CheckKind;
2347 if (ChecksEnabled[CK_MallocChecker])
2348 CheckKind = CK_MallocChecker;
2349 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2350 CheckKind = CK_MismatchedDeallocatorChecker;
2357 if (!BT_FreeAlloca[*CheckKind])
2358 BT_FreeAlloca[*CheckKind].reset(
new BugType(
2361 auto R = std::make_unique<PathSensitiveBugReport>(
2362 *BT_FreeAlloca[*CheckKind],
2363 "Memory allocated by alloca() should not be deallocated", N);
2366 C.emitReport(std::move(R));
2372 const Expr *DeallocExpr,
2374 bool OwnershipTransferred)
const {
2376 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2382 if (!BT_MismatchedDealloc)
2383 BT_MismatchedDealloc.reset(
2384 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2388 llvm::raw_svector_ostream os(buf);
2390 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2392 llvm::raw_svector_ostream AllocOs(AllocBuf);
2394 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2396 if (OwnershipTransferred) {
2398 os << DeallocOs.str() <<
" cannot";
2402 os <<
" take ownership of memory";
2405 os <<
" allocated by " << AllocOs.str();
2409 os <<
" allocated by " << AllocOs.str();
2411 os <<
" should be deallocated by ";
2415 os <<
", not " << DeallocOs.str();
2418 auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2420 R->markInteresting(Sym);
2422 R->addVisitor<MallocBugVisitor>(Sym);
2423 C.emitReport(std::move(R));
2429 AllocationFamily Family,
2430 const Expr *AllocExpr)
const {
2432 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2437 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2445 if (!BT_OffsetFree[*CheckKind])
2446 BT_OffsetFree[*CheckKind].reset(
new BugType(
2450 llvm::raw_svector_ostream os(buf);
2452 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2455 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2458 assert((Offset.isValid() &&
2459 !Offset.hasSymbolicOffset() &&
2460 Offset.getOffset() != 0) &&
2461 "Only symbols with a valid offset can have offset free errors");
2463 int offsetBytes = Offset.getOffset() /
C.getASTContext().getCharWidth();
2465 os <<
"Argument to ";
2467 os <<
"deallocator";
2468 os <<
" is offset by "
2471 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2472 <<
" from the start of ";
2474 os <<
"memory allocated by " << AllocNameOs.str();
2476 os <<
"allocated memory";
2478 auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2482 C.emitReport(std::move(R));
2488 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2489 !ChecksEnabled[CK_InnerPointerChecker]) {
2494 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2499 if (!BT_UseFree[*CheckKind])
2500 BT_UseFree[*CheckKind].reset(
new BugType(
2503 AllocationFamily AF =
2504 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2506 auto R = std::make_unique<PathSensitiveBugReport>(
2507 *BT_UseFree[*CheckKind],
2508 AF == AF_InnerBuffer
2509 ?
"Inner pointer of container used after re/deallocation"
2510 :
"Use of memory after it is freed",
2513 R->markInteresting(Sym);
2515 R->addVisitor<MallocBugVisitor>(Sym);
2517 if (AF == AF_InnerBuffer)
2520 C.emitReport(std::move(R));
2528 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2533 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2538 if (!BT_DoubleFree[*CheckKind])
2539 BT_DoubleFree[*CheckKind].reset(
new BugType(
2542 auto R = std::make_unique<PathSensitiveBugReport>(
2543 *BT_DoubleFree[*CheckKind],
2544 (Released ?
"Attempt to free released memory"
2545 :
"Attempt to free non-owned memory"),
2548 R->markInteresting(Sym);
2550 R->markInteresting(PrevSym);
2551 R->addVisitor<MallocBugVisitor>(Sym);
2552 C.emitReport(std::move(R));
2558 if (!ChecksEnabled[CK_NewDeleteChecker]) {
2563 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2568 if (!BT_DoubleDelete)
2569 BT_DoubleDelete.reset(
new BugType(CheckNames[CK_NewDeleteChecker],
2573 auto R = std::make_unique<PathSensitiveBugReport>(
2574 *BT_DoubleDelete,
"Attempt to delete released memory", N);
2576 R->markInteresting(Sym);
2577 R->addVisitor<MallocBugVisitor>(Sym);
2578 C.emitReport(std::move(R));
2585 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2590 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2596 if (!BT_UseZerroAllocated[*CheckKind])
2597 BT_UseZerroAllocated[*CheckKind].reset(
2598 new BugType(CheckNames[*CheckKind],
"Use of zero allocated",
2601 auto R = std::make_unique<PathSensitiveBugReport>(
2602 *BT_UseZerroAllocated[*CheckKind],
2603 "Use of memory allocated with size zero", N);
2607 R->markInteresting(Sym);
2608 R->addVisitor<MallocBugVisitor>(Sym);
2610 C.emitReport(std::move(R));
2616 const Expr *FreeExpr,
2617 AllocationFamily Family)
const {
2618 if (!ChecksEnabled[CK_MallocChecker]) {
2623 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2628 if (!BT_BadFree[*CheckKind])
2629 BT_BadFree[*CheckKind].reset(
new BugType(
2633 llvm::raw_svector_ostream Os(Buf);
2636 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2637 MR = ER->getSuperRegion();
2639 Os <<
"Argument to ";
2641 Os <<
"deallocator";
2643 Os <<
" is a function pointer";
2645 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2647 R->markInteresting(MR);
2649 C.emitReport(std::move(R));
2656 AllocationFamily Family,
bool SuffixWithN)
const {
2660 const CallExpr *CE = cast<CallExpr>(
Call.getOriginExpr());
2668 SVal Arg0Val =
C.getSVal(arg0Expr);
2669 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2676 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2682 SVal TotalSize =
C.getSVal(Arg1);
2684 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2685 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2691 svalBuilder.makeIntValWithWidth(
2692 svalBuilder.getContext().getSizeType(), 0));
2695 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2697 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2700 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2701 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2705 if (PrtIsNull && !SizeIsZero) {
2711 if (PrtIsNull && SizeIsZero)
2716 bool IsKnownToBeAllocated =
false;
2725 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2730 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2737 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2738 if (ShouldFreeOnFail)
2739 Kind = OAR_FreeOnFailure;
2740 else if (!IsKnownToBeAllocated)
2741 Kind = OAR_DoNotTrackAfterFailure;
2745 SVal RetVal =
C.getSVal(CE);
2747 assert(FromPtr && ToPtr &&
2748 "By this point, FreeMemAux and MallocMemAux should have checked "
2749 "whether the argument or the return value is symbolic!");
2753 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2754 ReallocPair(FromPtr, Kind));
2756 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2757 return stateRealloc;
2768 if (
Call.getNumArgs() < 2)
2774 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2776 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State, AF_Malloc);
2779MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2786 const MemRegion *ReferenceRegion =
nullptr;
2790 if (!State->get<RegionState>(Sym))
2795 if (!ReferenceRegion) {
2796 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
2797 SVal Val = State->getSVal(MR);
2803 ReferenceRegion = MR;
2811 if (NContext == LeakContext ||
2817 return LeakInfo(AllocNode, ReferenceRegion);
2823 if (!ChecksEnabled[CK_MallocChecker] &&
2824 !ChecksEnabled[CK_NewDeleteLeaksChecker])
2827 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2828 assert(RS &&
"cannot leak an untracked symbol");
2829 AllocationFamily Family = RS->getAllocationFamily();
2831 if (Family == AF_Alloca)
2834 std::optional<MallocChecker::CheckKind> CheckKind =
2835 getCheckIfTracked(Family,
true);
2841 if (!BT_Leak[*CheckKind]) {
2847 BT_Leak[*CheckKind].reset(
new BugType(CheckNames[*CheckKind],
"Memory leak",
2858 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
2863 C.getSourceManager(),
2867 llvm::raw_svector_ostream os(buf);
2869 os <<
"Potential leak of memory pointed to by ";
2872 os <<
"Potential memory leak";
2875 auto R = std::make_unique<PathSensitiveBugReport>(
2876 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
2878 R->markInteresting(Sym);
2879 R->addVisitor<MallocBugVisitor>(Sym,
true);
2880 if (ShouldRegisterNoOwnershipChangeVisitor)
2881 R->addVisitor<NoOwnershipChangeVisitor>(Sym,
this);
2882 C.emitReport(std::move(R));
2885void MallocChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
2889 RegionStateTy OldRS = state->get<RegionState>();
2890 RegionStateTy::Factory &F = state->get_context<RegionState>();
2892 RegionStateTy RS = OldRS;
2894 for (
auto [Sym, State] : RS) {
2895 if (SymReaper.
isDead(Sym)) {
2896 if (State.isAllocated() || State.isAllocatedOfSizeZero())
2897 Errors.push_back(Sym);
2899 RS = F.remove(RS, Sym);
2905 assert(state->get<ReallocPairs>() ==
2906 C.getState()->get<ReallocPairs>());
2907 assert(state->get<FreeReturnValue>() ==
2908 C.getState()->get<FreeReturnValue>());
2913 ReallocPairsTy RP = state->get<ReallocPairs>();
2914 for (
auto [Sym, ReallocPair] : RP) {
2915 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
2916 state = state->remove<ReallocPairs>(Sym);
2921 FreeReturnValueTy FR = state->get<FreeReturnValue>();
2922 for (
auto [Sym, RetSym] : FR) {
2923 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
2924 state = state->remove<FreeReturnValue>(Sym);
2930 if (!Errors.empty()) {
2932 N =
C.generateNonFatalErrorNode(
C.getState(), &Tag);
2935 HandleLeak(Sym, N,
C);
2940 C.addTransition(state->set<RegionState>(RS), N);
2946 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
2949 if (!ChecksEnabled[CK_NewDeleteChecker])
2957 bool IsKnownToBeAllocated;
2959 false, IsKnownToBeAllocated,
2960 (DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
2962 C.addTransition(State);
2966 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
2967 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
2968 if (!Sym || checkDoubleDelete(Sym,
C))
2974 if (
const auto *PreFN = PreFnMap.lookup(
Call)) {
2975 (*PreFN)(
this,
Call,
C);
2985 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(
Call))
2991 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
2992 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
2997 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
2999 if (isa<Loc>(ArgSVal)) {
3003 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3009void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3011 checkEscapeOnReturn(S,
C);
3017void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3019 checkEscapeOnReturn(S,
C);
3022void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3027 const Expr *E = S->getRetValue();
3033 SVal RetVal =
C.getSVal(E);
3040 if (isa<FieldRegion, ElementRegion>(MR))
3043 Sym = BMR->getSymbol();
3047 checkUseAfterFree(Sym,
C, E);
3053void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3063 cast<BlockDataRegion>(
C.getSVal(BE).getAsRegion());
3066 if (ReferencedVars.empty())
3073 for (
const auto &Var : ReferencedVars) {
3074 const VarRegion *VR = Var.getCapturedRegion();
3078 Regions.push_back(VR);
3082 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3083 C.addTransition(state);
3088 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3089 return (RS && RS->isReleased());
3092bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3094 if (
Call.getNumArgs() == 0)
3097 StringRef FunctionStr =
"";
3098 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3100 if (Body->getBeginLoc().isValid())
3104 C.getSourceManager(),
C.getLangOpts());
3107 if (!FunctionStr.contains(
"__isl_"))
3112 for (
const Expr *Arg : cast<CallExpr>(
Call.getOriginExpr())->arguments())
3113 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3114 if (
const RefState *RS = State->get<RegionState>(Sym))
3115 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3117 C.addTransition(State);
3122 const Stmt *S)
const {
3125 HandleUseAfterFree(
C, S->getSourceRange(), Sym);
3133 const Stmt *S)
const {
3136 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3137 if (RS->isAllocatedOfSizeZero())
3138 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3140 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3141 HandleUseZeroAlloc(
C, S->getSourceRange(), Sym);
3148 HandleDoubleDelete(
C, Sym);
3155void MallocChecker::checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
3159 checkUseAfterFree(Sym,
C, S);
3160 checkUseZeroAllocated(Sym,
C, S);
3168 bool Assumption)
const {
3169 RegionStateTy RS = state->get<RegionState>();
3170 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3175 state = state->remove<RegionState>(Sym);
3180 ReallocPairsTy RP = state->get<ReallocPairs>();
3181 for (
auto [Sym, ReallocPair] : RP) {
3188 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3189 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3190 if (RS->isReleased()) {
3191 switch (ReallocPair.Kind) {
3192 case OAR_ToBeFreedAfterFailure:
3193 state = state->set<RegionState>(ReallocSym,
3194 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3196 case OAR_DoNotTrackAfterFailure:
3197 state = state->remove<RegionState>(ReallocSym);
3200 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3204 state = state->remove<ReallocPairs>(Sym);
3210bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3215 EscapingSymbol =
nullptr;
3221 if (!isa<SimpleFunctionCall, ObjCMethodCall>(
Call))
3228 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3241 return *FreeWhenDone;
3247 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3248 if (FirstSlot.ends_with(
"NoCopy"))
3255 if (FirstSlot.starts_with(
"addPointer") ||
3256 FirstSlot.starts_with(
"insertPointer") ||
3257 FirstSlot.starts_with(
"replacePointer") ||
3258 FirstSlot ==
"valueWithPointer") {
3265 if (Msg->getMethodFamily() ==
OMF_init) {
3266 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3282 if (isMemCall(*
Call))
3286 if (!
Call->isInSystemHeader())
3293 StringRef FName = II->
getName();
3297 if (FName.ends_with(
"NoCopy")) {
3301 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3302 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3303 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3304 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3305 if (DeallocatorName ==
"kCFAllocatorNull")
3316 if (FName ==
"funopen")
3317 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3323 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3324 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3325 if (
Call->getNumArgs() >= 1) {
3326 const Expr *ArgE =
Call->getArgExpr(0)->IgnoreParenCasts();
3327 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3328 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3329 if (D->getCanonicalDecl()->getName().contains(
"std"))
3339 if (FName ==
"CGBitmapContextCreate" ||
3340 FName ==
"CGBitmapContextCreateWithData" ||
3341 FName ==
"CVPixelBufferCreateWithBytes" ||
3342 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3343 FName ==
"OSAtomicEnqueue") {
3347 if (FName ==
"postEvent" &&
3352 if (FName ==
"connectImpl" &&
3357 if (FName ==
"singleShotImpl" &&
3366 if (
Call->argumentsMayEscape())
3378 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3387 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3392 return (RS->getAllocationFamily() == AF_CXXNewArray ||
3393 RS->getAllocationFamily() == AF_CXXNew);
3399 bool IsConstPointerEscape)
const {
3404 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3411 if (EscapingSymbol && EscapingSymbol != sym)
3414 if (
const RefState *RS = State->get<RegionState>(sym))
3415 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3417 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3423 SVal ArgVal)
const {
3424 if (!KernelZeroSizePtrValue)
3425 KernelZeroSizePtrValue =
3428 const llvm::APSInt *ArgValKnown =
3429 C.getSValBuilder().getKnownValue(State, ArgVal);
3430 return ArgValKnown && *KernelZeroSizePtrValue &&
3431 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3436 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3437 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3439 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3441 if (!currMap.lookup(sym))
3451 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3452 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3453 N.contains_insensitive(
"intrusive") ||
3454 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3468 const RefState *RSCurr = state->get<RegionState>(Sym);
3469 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3474 if (!S && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer))
3486 if (ReleaseDestructorLC && (ReleaseDestructorLC == CurrentLC ||
3487 ReleaseDestructorLC->
isParentOf(CurrentLC))) {
3488 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3491 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3492 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3495 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
3498 if (
const auto *MD =
3515 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3517 llvm::raw_svector_ostream OS(Buf);
3520 if (isAllocated(RSCurr, RSPrev, S)) {
3521 Msg =
"Memory is allocated";
3522 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3523 Sym,
"Returned allocated memory");
3525 const auto Family = RSCurr->getAllocationFamily();
3530 case AF_CXXNewArray:
3531 case AF_IfNameIndex:
3532 Msg =
"Memory is released";
3533 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3534 Sym,
"Returning; memory was released");
3536 case AF_InnerBuffer: {
3539 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
3541 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
3544 OS <<
"deallocated by call to destructor";
3545 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3546 Sym,
"Returning; inner buffer was deallocated");
3548 OS <<
"reallocated by call to '";
3549 const Stmt *S = RSCurr->getStmt();
3550 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3551 OS << MemCallE->getMethodDecl()->getDeclName();
3552 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3553 OS << OpCallE->getDirectCallee()->getDeclName();
3554 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
3557 CEMgr.getSimpleCall(CallE, state, CurrentLC, {
nullptr, 0});
3558 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
3559 OS << D->getDeclName();
3564 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3565 Sym,
"Returning; inner buffer was reallocated");
3571 llvm_unreachable(
"Unhandled allocation family!");
3577 bool FoundAnyDestructor =
false;
3579 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
3585 }
else if (!FoundAnyDestructor) {
3586 assert(!ReleaseDestructorLC &&
3587 "There can be only one release point!");
3599 FoundAnyDestructor =
true;
3603 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
3604 Msg =
"Memory ownership is transferred";
3605 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
3606 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3607 Mode = ReallocationFailed;
3608 Msg =
"Reallocation failed";
3609 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3610 Sym,
"Reallocation failed");
3614 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3615 "We only support one failed realloc at a time.");
3617 FailedReallocSymbol = sym;
3622 }
else if (Mode == ReallocationFailed) {
3623 assert(FailedReallocSymbol &&
"No symbol to look for.");
3626 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3628 Msg =
"Attempt to reallocate memory";
3629 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3630 Sym,
"Returned reallocated memory");
3631 FailedReallocSymbol =
nullptr;
3646 assert(RSCurr->getAllocationFamily() == AF_InnerBuffer);
3657 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
3662void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
3663 const char *NL,
const char *Sep)
const {
3665 RegionStateTy RS = State->get<RegionState>();
3667 if (!RS.isEmpty()) {
3668 Out << Sep <<
"MallocChecker :" << NL;
3669 for (
auto [Sym,
Data] : RS) {
3670 const RefState *RefS = State->get<RegionState>(Sym);
3671 AllocationFamily Family = RefS->getAllocationFamily();
3672 std::optional<MallocChecker::CheckKind> CheckKind =
3673 getCheckIfTracked(Family);
3675 CheckKind = getCheckIfTracked(Family,
true);
3681 Out <<
" (" << CheckNames[*CheckKind].getName() <<
")";
3689namespace allocation_state {
3693 AllocationFamily Family = AF_InnerBuffer;
3694 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3704 MallocChecker *checker = mgr.
getChecker<MallocChecker>();
3705 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] =
true;
3706 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3712 checker->ShouldIncludeOwnershipAnnotatedFunctions =
3714 checker->ShouldRegisterNoOwnershipChangeVisitor =
3716 checker,
"AddNoOwnershipChangeNotes");
3719bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
3723#define REGISTER_CHECKER(name) \
3724 void ento::register##name(CheckerManager &mgr) { \
3725 MallocChecker *checker = mgr.getChecker<MallocChecker>(); \
3726 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
3727 checker->CheckNames[MallocChecker::CK_##name] = \
3728 mgr.getCurrentCheckerName(); \
3731 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.
llvm::MachO::Target Target
static bool isFromStdNamespace(const CallEvent &Call)
#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.
static bool contains(const std::set< tok::TokenKind > &Terminators, const Token &Tok)
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 C++ struct/union/class.
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.
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)
DeclContext * getParent()
getParent - Returns the containing DeclContext.
A reference to a declared variable, function, enum, etc.
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
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
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
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
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< 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.
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)
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
const FunctionProtoType * T
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.