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).equals(
"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);
1831 AllocationFamily Family,
1832 std::optional<SVal> RetVal) {
1838 RetVal =
C.getSVal(E);
1841 if (!RetVal->getAs<
Loc>())
1844 SymbolRef Sym = RetVal->getAsLocSymbol();
1859 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
1864 const OwnershipAttr *Att,
1869 if (Att->getModule()->getName() !=
"malloc")
1872 bool IsKnownToBeAllocated =
false;
1874 for (
const auto &Arg : Att->args()) {
1876 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
1877 Att->getOwnKind() == OwnershipAttr::Holds,
1878 IsKnownToBeAllocated, AF_Malloc);
1888 bool Hold,
bool &IsKnownToBeAllocated,
1889 AllocationFamily Family,
1890 bool ReturnsNullOnFailure)
const {
1894 if (
Call.getNumArgs() < (Num + 1))
1897 return FreeMemAux(
C,
Call.getArgExpr(Num),
Call, State, Hold,
1898 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
1905 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
1907 assert(*Ret &&
"We should not store the null return symbol");
1910 RetStatusSymbol = *Ret;
1917 if (
const CallExpr *CE = dyn_cast<CallExpr>(E)) {
1930 if (Msg->isInstanceMessage())
1934 Msg->getSelector().
print(os);
1938 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
1958 case AF_Malloc: os <<
"malloc()";
return;
1959 case AF_CXXNew: os <<
"'new'";
return;
1960 case AF_CXXNewArray: os <<
"'new[]'";
return;
1961 case AF_IfNameIndex: os <<
"'if_nameindex()'";
return;
1962 case AF_InnerBuffer: os <<
"container-specific allocator";
return;
1964 case AF_None: llvm_unreachable(
"not a deallocation expression");
1970 case AF_Malloc: os <<
"free()";
return;
1971 case AF_CXXNew: os <<
"'delete'";
return;
1972 case AF_CXXNewArray: os <<
"'delete[]'";
return;
1973 case AF_IfNameIndex: os <<
"'if_freenameindex()'";
return;
1974 case AF_InnerBuffer: os <<
"container-specific deallocator";
return;
1976 case AF_None: llvm_unreachable(
"suspicious argument");
1983 bool Hold,
bool &IsKnownToBeAllocated,
1984 AllocationFamily Family,
bool ReturnsNullOnFailure,
1985 std::optional<SVal> ArgValOpt)
const {
1990 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
1991 if (!isa<DefinedOrUnknownSVal>(ArgVal))
1996 if (!isa<Loc>(location))
2001 std::tie(notNullState, nullState) = State->assume(location);
2002 if (nullState && !notNullState)
2011 const Expr *ParentExpr =
Call.getOriginExpr();
2030 if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2031 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2039 if (isa<BlockDataRegion>(R)) {
2040 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2049 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
2055 if (isa<AllocaRegion>(R))
2058 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2071 const RefState *RsBase = State->get<RegionState>(SymBase);
2072 SymbolRef PreviousRetStatusSymbol =
nullptr;
2074 IsKnownToBeAllocated =
2075 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2080 if (RsBase->getAllocationFamily() == AF_Alloca) {
2086 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2088 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2089 SymBase, PreviousRetStatusSymbol);
2094 }
else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2095 RsBase->isEscaped()) {
2098 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2099 if (!DeallocMatchesAlloc) {
2101 RsBase, SymBase, Hold);
2108 if (Offset.isValid() &&
2109 !Offset.hasSymbolicOffset() &&
2110 Offset.getOffset() != 0) {
2111 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2120 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2126 State = State->remove<FreeReturnValue>(SymBase);
2130 if (ReturnsNullOnFailure) {
2131 SVal RetVal =
C.getSVal(ParentExpr);
2133 if (RetStatusSymbol) {
2134 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2135 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2143 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2147 return State->set<RegionState>(SymBase,
2148 RefState::getRelinquished(Family,
2151 return State->set<RegionState>(SymBase,
2152 RefState::getReleased(Family, ParentExpr));
2155std::optional<MallocChecker::CheckKind>
2156MallocChecker::getCheckIfTracked(AllocationFamily Family,
2157 bool IsALeakCheck)
const {
2161 case AF_IfNameIndex: {
2162 if (ChecksEnabled[CK_MallocChecker])
2163 return CK_MallocChecker;
2164 return std::nullopt;
2167 case AF_CXXNewArray: {
2169 if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2170 return CK_NewDeleteLeaksChecker;
2173 if (ChecksEnabled[CK_NewDeleteChecker])
2174 return CK_NewDeleteChecker;
2176 return std::nullopt;
2178 case AF_InnerBuffer: {
2179 if (ChecksEnabled[CK_InnerPointerChecker])
2180 return CK_InnerPointerChecker;
2181 return std::nullopt;
2184 llvm_unreachable(
"no family");
2187 llvm_unreachable(
"unhandled family");
2190std::optional<MallocChecker::CheckKind>
2192 bool IsALeakCheck)
const {
2193 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2194 return CK_MallocChecker;
2196 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2198 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2201bool MallocChecker::SummarizeValue(raw_ostream &os,
SVal V) {
2202 if (std::optional<nonloc::ConcreteInt> IntVal =
2204 os <<
"an integer (" << IntVal->getValue() <<
")";
2205 else if (std::optional<loc::ConcreteInt> ConstAddr =
2207 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2209 os <<
"the address of the label '" <<
Label->getLabel()->getName() <<
"'";
2216bool MallocChecker::SummarizeRegion(raw_ostream &os,
2219 case MemRegion::FunctionCodeRegionKind: {
2220 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2222 os <<
"the address of the function '" << *FD <<
'\'';
2224 os <<
"the address of a function";
2227 case MemRegion::BlockCodeRegionKind:
2230 case MemRegion::BlockDataRegionKind:
2237 if (isa<StackLocalsSpaceRegion>(MS)) {
2238 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2246 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2248 os <<
"the address of a local stack variable";
2252 if (isa<StackArgumentsSpaceRegion>(MS)) {
2253 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2261 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2263 os <<
"the address of a parameter";
2267 if (isa<GlobalsSpaceRegion>(MS)) {
2268 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2277 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2279 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2281 os <<
"the address of a global variable";
2292 const Expr *DeallocExpr,
2293 AllocationFamily Family)
const {
2295 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2300 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2305 if (!BT_BadFree[*CheckKind])
2306 BT_BadFree[*CheckKind].reset(
new BugType(
2310 llvm::raw_svector_ostream os(buf);
2313 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2314 MR = ER->getSuperRegion();
2316 os <<
"Argument to ";
2318 os <<
"deallocator";
2321 bool Summarized = MR ? SummarizeRegion(os, MR)
2322 : SummarizeValue(os, ArgVal);
2324 os <<
", which is not memory allocated by ";
2326 os <<
"not memory allocated by ";
2330 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2332 R->markInteresting(MR);
2334 C.emitReport(std::move(R));
2341 std::optional<MallocChecker::CheckKind> CheckKind;
2343 if (ChecksEnabled[CK_MallocChecker])
2344 CheckKind = CK_MallocChecker;
2345 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2346 CheckKind = CK_MismatchedDeallocatorChecker;
2353 if (!BT_FreeAlloca[*CheckKind])
2354 BT_FreeAlloca[*CheckKind].reset(
new BugType(
2357 auto R = std::make_unique<PathSensitiveBugReport>(
2358 *BT_FreeAlloca[*CheckKind],
2359 "Memory allocated by alloca() should not be deallocated", N);
2362 C.emitReport(std::move(R));
2368 const Expr *DeallocExpr,
2370 bool OwnershipTransferred)
const {
2372 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2378 if (!BT_MismatchedDealloc)
2379 BT_MismatchedDealloc.reset(
2380 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2384 llvm::raw_svector_ostream os(buf);
2386 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2388 llvm::raw_svector_ostream AllocOs(AllocBuf);
2390 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2392 if (OwnershipTransferred) {
2394 os << DeallocOs.str() <<
" cannot";
2398 os <<
" take ownership of memory";
2401 os <<
" allocated by " << AllocOs.str();
2405 os <<
" allocated by " << AllocOs.str();
2407 os <<
" should be deallocated by ";
2411 os <<
", not " << DeallocOs.str();
2414 auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2416 R->markInteresting(Sym);
2418 R->addVisitor<MallocBugVisitor>(Sym);
2419 C.emitReport(std::move(R));
2425 AllocationFamily Family,
2426 const Expr *AllocExpr)
const {
2428 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2433 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2441 if (!BT_OffsetFree[*CheckKind])
2442 BT_OffsetFree[*CheckKind].reset(
new BugType(
2446 llvm::raw_svector_ostream os(buf);
2448 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2451 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2454 assert((Offset.isValid() &&
2455 !Offset.hasSymbolicOffset() &&
2456 Offset.getOffset() != 0) &&
2457 "Only symbols with a valid offset can have offset free errors");
2459 int offsetBytes = Offset.getOffset() /
C.getASTContext().getCharWidth();
2461 os <<
"Argument to ";
2463 os <<
"deallocator";
2464 os <<
" is offset by "
2467 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2468 <<
" from the start of ";
2470 os <<
"memory allocated by " << AllocNameOs.str();
2472 os <<
"allocated memory";
2474 auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2478 C.emitReport(std::move(R));
2484 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2485 !ChecksEnabled[CK_InnerPointerChecker]) {
2490 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2495 if (!BT_UseFree[*CheckKind])
2496 BT_UseFree[*CheckKind].reset(
new BugType(
2499 AllocationFamily AF =
2500 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2502 auto R = std::make_unique<PathSensitiveBugReport>(
2503 *BT_UseFree[*CheckKind],
2504 AF == AF_InnerBuffer
2505 ?
"Inner pointer of container used after re/deallocation"
2506 :
"Use of memory after it is freed",
2509 R->markInteresting(Sym);
2511 R->addVisitor<MallocBugVisitor>(Sym);
2513 if (AF == AF_InnerBuffer)
2516 C.emitReport(std::move(R));
2524 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2529 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2534 if (!BT_DoubleFree[*CheckKind])
2535 BT_DoubleFree[*CheckKind].reset(
new BugType(
2538 auto R = std::make_unique<PathSensitiveBugReport>(
2539 *BT_DoubleFree[*CheckKind],
2540 (Released ?
"Attempt to free released memory"
2541 :
"Attempt to free non-owned memory"),
2544 R->markInteresting(Sym);
2546 R->markInteresting(PrevSym);
2547 R->addVisitor<MallocBugVisitor>(Sym);
2548 C.emitReport(std::move(R));
2554 if (!ChecksEnabled[CK_NewDeleteChecker]) {
2559 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2564 if (!BT_DoubleDelete)
2565 BT_DoubleDelete.reset(
new BugType(CheckNames[CK_NewDeleteChecker],
2569 auto R = std::make_unique<PathSensitiveBugReport>(
2570 *BT_DoubleDelete,
"Attempt to delete released memory", N);
2572 R->markInteresting(Sym);
2573 R->addVisitor<MallocBugVisitor>(Sym);
2574 C.emitReport(std::move(R));
2581 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2586 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2592 if (!BT_UseZerroAllocated[*CheckKind])
2593 BT_UseZerroAllocated[*CheckKind].reset(
2594 new BugType(CheckNames[*CheckKind],
"Use of zero allocated",
2597 auto R = std::make_unique<PathSensitiveBugReport>(
2598 *BT_UseZerroAllocated[*CheckKind],
2599 "Use of memory allocated with size zero", N);
2603 R->markInteresting(Sym);
2604 R->addVisitor<MallocBugVisitor>(Sym);
2606 C.emitReport(std::move(R));
2612 const Expr *FreeExpr,
2613 AllocationFamily Family)
const {
2614 if (!ChecksEnabled[CK_MallocChecker]) {
2619 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2624 if (!BT_BadFree[*CheckKind])
2625 BT_BadFree[*CheckKind].reset(
new BugType(
2629 llvm::raw_svector_ostream Os(Buf);
2632 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2633 MR = ER->getSuperRegion();
2635 Os <<
"Argument to ";
2637 Os <<
"deallocator";
2639 Os <<
" is a function pointer";
2641 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2643 R->markInteresting(MR);
2645 C.emitReport(std::move(R));
2652 AllocationFamily Family,
bool SuffixWithN)
const {
2656 const CallExpr *CE = cast<CallExpr>(
Call.getOriginExpr());
2664 SVal Arg0Val =
C.getSVal(arg0Expr);
2665 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2672 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2678 SVal TotalSize =
C.getSVal(Arg1);
2680 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2681 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2687 svalBuilder.makeIntValWithWidth(
2688 svalBuilder.getContext().getSizeType(), 0));
2691 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2693 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2696 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2697 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2701 if (PrtIsNull && !SizeIsZero) {
2707 if (PrtIsNull && SizeIsZero)
2712 bool IsKnownToBeAllocated =
false;
2721 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2726 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2733 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2734 if (ShouldFreeOnFail)
2735 Kind = OAR_FreeOnFailure;
2736 else if (!IsKnownToBeAllocated)
2737 Kind = OAR_DoNotTrackAfterFailure;
2741 SVal RetVal =
C.getSVal(CE);
2743 assert(FromPtr && ToPtr &&
2744 "By this point, FreeMemAux and MallocMemAux should have checked "
2745 "whether the argument or the return value is symbolic!");
2749 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2750 ReallocPair(FromPtr, Kind));
2752 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2753 return stateRealloc;
2764 if (
Call.getNumArgs() < 2)
2770 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2772 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State, AF_Malloc);
2775MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2782 const MemRegion *ReferenceRegion =
nullptr;
2786 if (!State->get<RegionState>(Sym))
2791 if (!ReferenceRegion) {
2792 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
2793 SVal Val = State->getSVal(MR);
2799 ReferenceRegion = MR;
2807 if (NContext == LeakContext ||
2813 return LeakInfo(AllocNode, ReferenceRegion);
2819 if (!ChecksEnabled[CK_MallocChecker] &&
2820 !ChecksEnabled[CK_NewDeleteLeaksChecker])
2823 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2824 assert(RS &&
"cannot leak an untracked symbol");
2825 AllocationFamily Family = RS->getAllocationFamily();
2827 if (Family == AF_Alloca)
2830 std::optional<MallocChecker::CheckKind> CheckKind =
2831 getCheckIfTracked(Family,
true);
2837 if (!BT_Leak[*CheckKind]) {
2843 BT_Leak[*CheckKind].reset(
new BugType(CheckNames[*CheckKind],
"Memory leak",
2854 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
2859 C.getSourceManager(),
2863 llvm::raw_svector_ostream os(buf);
2865 os <<
"Potential leak of memory pointed to by ";
2868 os <<
"Potential memory leak";
2871 auto R = std::make_unique<PathSensitiveBugReport>(
2872 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
2874 R->markInteresting(Sym);
2875 R->addVisitor<MallocBugVisitor>(Sym,
true);
2876 if (ShouldRegisterNoOwnershipChangeVisitor)
2877 R->addVisitor<NoOwnershipChangeVisitor>(Sym,
this);
2878 C.emitReport(std::move(R));
2881void MallocChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
2885 RegionStateTy OldRS = state->get<RegionState>();
2886 RegionStateTy::Factory &F = state->get_context<RegionState>();
2888 RegionStateTy RS = OldRS;
2890 for (
auto [Sym, State] : RS) {
2891 if (SymReaper.
isDead(Sym)) {
2892 if (State.isAllocated() || State.isAllocatedOfSizeZero())
2893 Errors.push_back(Sym);
2895 RS = F.remove(RS, Sym);
2901 assert(state->get<ReallocPairs>() ==
2902 C.getState()->get<ReallocPairs>());
2903 assert(state->get<FreeReturnValue>() ==
2904 C.getState()->get<FreeReturnValue>());
2909 ReallocPairsTy RP = state->get<ReallocPairs>();
2910 for (
auto [Sym, ReallocPair] : RP) {
2911 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
2912 state = state->remove<ReallocPairs>(Sym);
2917 FreeReturnValueTy FR = state->get<FreeReturnValue>();
2918 for (
auto [Sym, RetSym] : FR) {
2919 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
2920 state = state->remove<FreeReturnValue>(Sym);
2926 if (!Errors.empty()) {
2928 N =
C.generateNonFatalErrorNode(
C.getState(), &Tag);
2931 HandleLeak(Sym, N,
C);
2936 C.addTransition(state->set<RegionState>(RS), N);
2942 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
2945 if (!ChecksEnabled[CK_NewDeleteChecker])
2953 bool IsKnownToBeAllocated;
2955 false, IsKnownToBeAllocated,
2956 (DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
2958 C.addTransition(State);
2962 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
2963 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
2964 if (!Sym || checkDoubleDelete(Sym,
C))
2970 if (
const auto *PreFN = PreFnMap.lookup(
Call)) {
2971 (*PreFN)(
this,
Call,
C);
2981 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(
Call))
2987 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
2988 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
2993 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
2995 if (isa<Loc>(ArgSVal)) {
2999 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3005void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3007 checkEscapeOnReturn(S,
C);
3013void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3015 checkEscapeOnReturn(S,
C);
3018void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3023 const Expr *E = S->getRetValue();
3029 SVal RetVal =
C.getSVal(E);
3036 if (isa<FieldRegion, ElementRegion>(MR))
3039 Sym = BMR->getSymbol();
3043 checkUseAfterFree(Sym,
C, E);
3049void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3059 cast<BlockDataRegion>(
C.getSVal(BE).getAsRegion());
3062 if (ReferencedVars.empty())
3069 for (
const auto &Var : ReferencedVars) {
3070 const VarRegion *VR = Var.getCapturedRegion();
3074 Regions.push_back(VR);
3078 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3079 C.addTransition(state);
3084 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3085 return (RS && RS->isReleased());
3088bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3090 if (
Call.getNumArgs() == 0)
3093 StringRef FunctionStr =
"";
3094 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3096 if (Body->getBeginLoc().isValid())
3100 C.getSourceManager(),
C.getLangOpts());
3103 if (!FunctionStr.contains(
"__isl_"))
3108 for (
const Expr *Arg : cast<CallExpr>(
Call.getOriginExpr())->arguments())
3109 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3110 if (
const RefState *RS = State->get<RegionState>(Sym))
3111 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3113 C.addTransition(State);
3118 const Stmt *S)
const {
3121 HandleUseAfterFree(
C, S->getSourceRange(), Sym);
3129 const Stmt *S)
const {
3132 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3133 if (RS->isAllocatedOfSizeZero())
3134 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3136 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3137 HandleUseZeroAlloc(
C, S->getSourceRange(), Sym);
3144 HandleDoubleDelete(
C, Sym);
3151void MallocChecker::checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
3155 checkUseAfterFree(Sym,
C, S);
3156 checkUseZeroAllocated(Sym,
C, S);
3164 bool Assumption)
const {
3165 RegionStateTy RS = state->get<RegionState>();
3166 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3171 state = state->remove<RegionState>(Sym);
3176 ReallocPairsTy RP = state->get<ReallocPairs>();
3177 for (
auto [Sym, ReallocPair] : RP) {
3184 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3185 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3186 if (RS->isReleased()) {
3187 switch (ReallocPair.Kind) {
3188 case OAR_ToBeFreedAfterFailure:
3189 state = state->set<RegionState>(ReallocSym,
3190 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3192 case OAR_DoNotTrackAfterFailure:
3193 state = state->remove<RegionState>(ReallocSym);
3196 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3200 state = state->remove<ReallocPairs>(Sym);
3206bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3211 EscapingSymbol =
nullptr;
3217 if (!isa<SimpleFunctionCall, ObjCMethodCall>(
Call))
3224 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3237 return *FreeWhenDone;
3243 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3244 if (FirstSlot.ends_with(
"NoCopy"))
3251 if (FirstSlot.starts_with(
"addPointer") ||
3252 FirstSlot.starts_with(
"insertPointer") ||
3253 FirstSlot.starts_with(
"replacePointer") ||
3254 FirstSlot.equals(
"valueWithPointer")) {
3261 if (Msg->getMethodFamily() ==
OMF_init) {
3262 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3278 if (isMemCall(*
Call))
3282 if (!
Call->isInSystemHeader())
3289 StringRef FName = II->
getName();
3293 if (FName.ends_with(
"NoCopy")) {
3297 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3298 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3299 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3300 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3301 if (DeallocatorName ==
"kCFAllocatorNull")
3312 if (FName ==
"funopen")
3313 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3319 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3320 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3321 if (
Call->getNumArgs() >= 1) {
3322 const Expr *ArgE =
Call->getArgExpr(0)->IgnoreParenCasts();
3323 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3324 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3325 if (D->getCanonicalDecl()->getName().contains(
"std"))
3335 if (FName ==
"CGBitmapContextCreate" ||
3336 FName ==
"CGBitmapContextCreateWithData" ||
3337 FName ==
"CVPixelBufferCreateWithBytes" ||
3338 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3339 FName ==
"OSAtomicEnqueue") {
3343 if (FName ==
"postEvent" &&
3348 if (FName ==
"connectImpl" &&
3353 if (FName ==
"singleShotImpl" &&
3362 if (
Call->argumentsMayEscape())
3374 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3383 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3388 return (RS->getAllocationFamily() == AF_CXXNewArray ||
3389 RS->getAllocationFamily() == AF_CXXNew);
3395 bool IsConstPointerEscape)
const {
3400 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3407 if (EscapingSymbol && EscapingSymbol != sym)
3410 if (
const RefState *RS = State->get<RegionState>(sym))
3411 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3413 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3419 SVal ArgVal)
const {
3420 if (!KernelZeroSizePtrValue)
3421 KernelZeroSizePtrValue =
3424 const llvm::APSInt *ArgValKnown =
3425 C.getSValBuilder().getKnownValue(State, ArgVal);
3426 return ArgValKnown && *KernelZeroSizePtrValue &&
3427 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3432 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3433 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3435 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3437 if (!currMap.lookup(sym))
3447 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3448 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3449 N.contains_insensitive(
"intrusive") ||
3450 N.contains_insensitive(
"shared")) {
3464 const RefState *RSCurr = state->get<RegionState>(Sym);
3465 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3470 if (!S && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer))
3482 if (ReleaseDestructorLC) {
3483 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3485 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3486 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3487 if (ReleaseDestructorLC == CurrentLC ||
3488 ReleaseDestructorLC->
isParentOf(CurrentLC)) {
3500 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3502 llvm::raw_svector_ostream OS(Buf);
3505 if (isAllocated(RSCurr, RSPrev, S)) {
3506 Msg =
"Memory is allocated";
3507 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3508 Sym,
"Returned allocated memory");
3510 const auto Family = RSCurr->getAllocationFamily();
3515 case AF_CXXNewArray:
3516 case AF_IfNameIndex:
3517 Msg =
"Memory is released";
3518 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3519 Sym,
"Returning; memory was released");
3521 case AF_InnerBuffer: {
3524 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
3526 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
3529 OS <<
"deallocated by call to destructor";
3530 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3531 Sym,
"Returning; inner buffer was deallocated");
3533 OS <<
"reallocated by call to '";
3534 const Stmt *S = RSCurr->getStmt();
3535 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3536 OS << MemCallE->getMethodDecl()->getDeclName();
3537 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3538 OS << OpCallE->getDirectCallee()->getDeclName();
3539 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
3542 CEMgr.getSimpleCall(CallE, state, CurrentLC, {
nullptr, 0});
3543 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
3544 OS << D->getDeclName();
3549 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3550 Sym,
"Returning; inner buffer was reallocated");
3556 llvm_unreachable(
"Unhandled allocation family!");
3562 bool FoundAnyDestructor =
false;
3564 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
3570 }
else if (!FoundAnyDestructor) {
3571 assert(!ReleaseDestructorLC &&
3572 "There can be only one release point!");
3584 FoundAnyDestructor =
true;
3588 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
3589 Msg =
"Memory ownership is transferred";
3590 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
3591 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3592 Mode = ReallocationFailed;
3593 Msg =
"Reallocation failed";
3594 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3595 Sym,
"Reallocation failed");
3599 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3600 "We only support one failed realloc at a time.");
3602 FailedReallocSymbol = sym;
3607 }
else if (Mode == ReallocationFailed) {
3608 assert(FailedReallocSymbol &&
"No symbol to look for.");
3611 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3613 Msg =
"Attempt to reallocate memory";
3614 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3615 Sym,
"Returned reallocated memory");
3616 FailedReallocSymbol =
nullptr;
3631 assert(RSCurr->getAllocationFamily() == AF_InnerBuffer);
3642 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
3647void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
3648 const char *NL,
const char *Sep)
const {
3650 RegionStateTy RS = State->get<RegionState>();
3652 if (!RS.isEmpty()) {
3653 Out << Sep <<
"MallocChecker :" << NL;
3654 for (
auto [Sym,
Data] : RS) {
3655 const RefState *RefS = State->get<RegionState>(Sym);
3656 AllocationFamily Family = RefS->getAllocationFamily();
3657 std::optional<MallocChecker::CheckKind> CheckKind =
3658 getCheckIfTracked(Family);
3660 CheckKind = getCheckIfTracked(Family,
true);
3666 Out <<
" (" << CheckNames[*CheckKind].getName() <<
")";
3674namespace allocation_state {
3678 AllocationFamily Family = AF_InnerBuffer;
3679 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3689 MallocChecker *checker = mgr.
getChecker<MallocChecker>();
3690 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] =
true;
3691 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3697 checker->ShouldIncludeOwnershipAnnotatedFunctions =
3699 checker->ShouldRegisterNoOwnershipChangeVisitor =
3701 checker,
"AddNoOwnershipChangeNotes");
3704bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
3708#define REGISTER_CHECKER(name) \
3709 void ento::register##name(CheckerManager &mgr) { \
3710 MallocChecker *checker = mgr.getChecker<MallocChecker>(); \
3711 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
3712 checker->CheckNames[MallocChecker::CK_##name] = \
3713 mgr.getCurrentCheckerName(); \
3716 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.
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.
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
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.