79#include "llvm/ADT/STLExtras.h"
80#include "llvm/ADT/SetOperations.h"
81#include "llvm/ADT/SmallString.h"
82#include "llvm/ADT/StringExtras.h"
83#include "llvm/Support/Casting.h"
84#include "llvm/Support/Compiler.h"
85#include "llvm/Support/ErrorHandling.h"
86#include "llvm/Support/raw_ostream.h"
94using namespace std::placeholders;
106enum AllocationFamily {
157 AllocationFamily Family;
159 RefState(Kind k,
const Stmt *
s, AllocationFamily family)
160 : S(
s), K(k), Family(family) {
161 assert(family != AF_None);
165 bool isAllocated()
const {
return K == Allocated; }
166 bool isAllocatedOfSizeZero()
const {
return K == AllocatedOfSizeZero; }
167 bool isReleased()
const {
return K == Released; }
168 bool isRelinquished()
const {
return K == Relinquished; }
169 bool isEscaped()
const {
return K == Escaped; }
170 AllocationFamily getAllocationFamily()
const {
return Family; }
171 const Stmt *getStmt()
const {
return S; }
174 return K ==
X.K && S ==
X.S && Family ==
X.Family;
177 static RefState getAllocated(AllocationFamily family,
const Stmt *
s) {
178 return RefState(Allocated,
s, family);
180 static RefState getAllocatedOfSizeZero(
const RefState *RS) {
181 return RefState(AllocatedOfSizeZero, RS->getStmt(),
182 RS->getAllocationFamily());
184 static RefState getReleased(AllocationFamily family,
const Stmt *
s) {
185 return RefState(Released,
s, family);
187 static RefState getRelinquished(AllocationFamily family,
const Stmt *
s) {
188 return RefState(Relinquished,
s, family);
190 static RefState getEscaped(
const RefState *RS) {
191 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
194 void Profile(llvm::FoldingSetNodeID &ID)
const {
197 ID.AddInteger(Family);
200 LLVM_DUMP_METHOD
void dump(raw_ostream &
OS)
const {
202#define CASE(ID) case ID: OS << #ID; break;
204 CASE(AllocatedOfSizeZero)
211 LLVM_DUMP_METHOD
void dump()
const {
dump(llvm::errs()); }
226 AllocationFamily Family,
227 std::optional<SVal> RetVal = std::nullopt);
241enum OwnershipAfterReallocKind {
243 OAR_ToBeFreedAfterFailure,
253 OAR_DoNotTrackAfterFailure
266 OwnershipAfterReallocKind
Kind;
268 ReallocPair(
SymbolRef S, OwnershipAfterReallocKind K)
269 : ReallocatedSym(S),
Kind(K) {}
270 void Profile(llvm::FoldingSetNodeID &ID)
const {
272 ID.AddPointer(ReallocatedSym);
275 return ReallocatedSym ==
X.ReallocatedSym &&
288 if (!Call.getDecl() || !isa<FunctionDecl>(Call.getDecl()))
300 :
public Checker<check::DeadSymbols, check::PointerEscape,
301 check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
302 check::EndFunction, check::PreCall, check::PostCall,
303 check::NewAllocator, check::PostStmt<BlockExpr>,
304 check::PostObjCMessage, check::Location, eval::Assume> {
310 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
312 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
322 CK_NewDeleteLeaksChecker,
323 CK_MismatchedDeallocatorChecker,
324 CK_InnerPointerChecker,
328 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
330 bool ChecksEnabled[CK_NumCheckKinds] = {
false};
342 bool Assumption)
const;
343 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
356 const char *NL,
const char *Sep)
const override;
359 mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];
360 mutable std::unique_ptr<BugType> BT_DoubleDelete;
361 mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];
362 mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];
363 mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
364 mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
365 mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
366 mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
367 mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
369#define CHECK_FN(NAME) \
370 void NAME(const CallEvent &Call, CheckerContext &C) const;
389 bool ShouldFreeOnFail)
const;
391 using CheckFn = std::function<void(
const MallocChecker *,
395 {{{
"free"}, 1}, &MallocChecker::checkFree},
396 {{{
"if_freenameindex"}, 1}, &MallocChecker::checkIfFreeNameIndex},
397 {{{
"kfree"}, 1}, &MallocChecker::checkFree},
398 {{{
"g_free"}, 1}, &MallocChecker::checkFree},
401 bool isFreeingCall(
const CallEvent &Call)
const;
402 static bool isFreeingOwnershipAttrCall(
const FunctionDecl *Func);
404 friend class NoOwnershipChangeVisitor;
407 {{{
"alloca"}, 1}, &MallocChecker::checkAlloca},
408 {{{
"_alloca"}, 1}, &MallocChecker::checkAlloca},
409 {{{
"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
410 {{{
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
411 {{{
"calloc"}, 2}, &MallocChecker::checkCalloc},
412 {{{
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
415 {{{
"_strdup"}, 1}, &MallocChecker::checkStrdup},
416 {{{
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
417 {{{
"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
420 {{{
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
421 {{{
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
422 {{{
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
423 {{{
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
424 {{{
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
425 {{{
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
426 {{{
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
427 {{{
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
428 {{{
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
433 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
435 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
true)},
437 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
438 {{{
"g_try_realloc"}, 2},
439 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
440 {{{
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
441 {{{
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
444 bool isMemCall(
const CallEvent &Call)
const;
447 mutable std::optional<uint64_t> KernelZeroFlagVal;
449 using KernelZeroSizePtrValueTy = std::optional<int>;
454 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
460 AllocationFamily Family)
const;
471 ProcessZeroAllocCheck(
const CallEvent &Call,
const unsigned IndexOfSizeArg,
473 std::optional<SVal> RetVal = std::nullopt);
523 [[nodiscard]] std::optional<ProgramStateRef>
546 const OwnershipAttr *Att,
570 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
571 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
595 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
613 bool SuffixWithN =
false)
const;
622 const Expr *BlockBytes);
634 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &Call,
643 const Stmt *S)
const;
658 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *Call,
667 bool IsConstPointerEscape)
const;
676 std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
677 bool IsALeakCheck =
false)
const;
680 bool IsALeakCheck =
false)
const;
682 static bool SummarizeValue(raw_ostream &os,
SVal V);
683 static bool SummarizeRegion(raw_ostream &os,
const MemRegion *MR);
686 const Expr *DeallocExpr,
687 AllocationFamily Family)
const;
693 const Expr *DeallocExpr,
const RefState *RS,
694 SymbolRef Sym,
bool OwnershipTransferred)
const;
697 const Expr *DeallocExpr, AllocationFamily Family,
698 const Expr *AllocExpr =
nullptr)
const;
712 const Expr *FreeExpr,
713 AllocationFamily Family)
const;
746 OwnershipBindingsHandler(
SymbolRef Sym, OwnerSet &Owners)
747 : Sym(Sym), Owners(Owners) {}
752 Owners.insert(Region);
756 LLVM_DUMP_METHOD
void dump()
const { dumpToStream(llvm::errs()); }
757 LLVM_DUMP_METHOD
void dumpToStream(llvm::raw_ostream &out)
const {
758 out <<
"Owners: {\n";
761 Owner->dumpToStream(out);
773 OwnershipBindingsHandler Handler{Sym,
Ret};
774 State->getStateManager().getStoreManager().iterBindings(State->getStore(),
779 LLVM_DUMP_METHOD
static std::string
781 if (
const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>(
784 return FD->getQualifiedNameAsString();
795 bool isFreeingCallAsWritten(
const CallExpr &Call)
const {
796 if (
Checker.FreeingMemFnMap.lookupAsWritten(Call) ||
797 Checker.ReallocatingMemFnMap.lookupAsWritten(Call))
800 if (
const auto *Func =
801 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
802 return MallocChecker::isFreeingOwnershipAttrCall(Func);
811 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
ASTContext &ACtx) {
813 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
831 if (
const auto *Call = Match.getNodeAs<
CallExpr>(
"call"))
832 if (isFreeingCallAsWritten(*Call))
841 bool wasModifiedInFunction(
const ExplodedNode *CallEnterN,
843 if (!doesFnIntendToHandleOwnership(
845 CallExitEndN->
getState()->getAnalysisManager().getASTContext()))
848 if (CallEnterN->
getState()->get<RegionState>(Sym) !=
849 CallExitEndN->
getState()->get<RegionState>(Sym))
852 OwnerSet CurrOwners = getOwnersAtNode(CallEnterN);
853 OwnerSet ExitOwners = getOwnersAtNode(CallExitEndN);
861 return !llvm::set_is_subset(ExitOwners, CurrOwners);
867 N->
getState()->getStateManager().getContext().getSourceManager());
868 return std::make_shared<PathDiagnosticEventPiece>(
869 L,
"Returning without deallocating memory or storing the pointer for "
870 "later deallocation");
897 for (
unsigned I = 0; I <
Call.getNumArgs() && I <
Parameters.size(); ++I) {
899 if (
V.getAsSymbol() == Sym)
910 void Profile(llvm::FoldingSetNodeID &ID)
const override {
929 enum NotificationMode {
Normal, ReallocationFailed };
935 NotificationMode Mode;
947 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
948 : Sym(S), Mode(
Normal), FailedReallocSymbol(nullptr),
949 ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
951 static void *getTag() {
956 void Profile(llvm::FoldingSetNodeID &ID)
const override {
957 ID.AddPointer(getTag());
962 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
964 return (isa_and_nonnull<CallExpr, CXXNewExpr>(
Stmt) &&
966 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
968 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
973 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
976 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
977 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(
Stmt)) ||
978 (!
Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer));
983 static inline bool isRelinquished(
const RefState *RSCurr,
984 const RefState *RSPrev,
const Stmt *
Stmt) {
986 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(
Stmt) &&
987 (RSCurr && RSCurr->isRelinquished()) &&
988 (!RSPrev || !RSPrev->isRelinquished()));
995 static inline bool hasReallocFailed(
const RefState *RSCurr,
996 const RefState *RSPrev,
998 return ((!isa_and_nonnull<CallExpr>(
Stmt)) &&
1000 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1002 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1017 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1022 class StackHintGeneratorForReallocationFailed
1025 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1028 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1033 llvm::raw_svector_ostream os(buf);
1035 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1036 <<
" parameter failed";
1038 return std::string(os.str());
1042 return "Reallocation of returned value failed";
1061 state = state->remove<RegionState>(sym);
1072 if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete &&
1073 Kind != OO_Array_Delete)
1088bool MallocChecker::isFreeingOwnershipAttrCall(
const FunctionDecl *Func) {
1091 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1092 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1099bool MallocChecker::isFreeingCall(
const CallEvent &Call)
const {
1100 if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
1103 if (
const auto *Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl()))
1104 return isFreeingOwnershipAttrCall(Func);
1109bool MallocChecker::isMemCall(
const CallEvent &Call)
const {
1110 if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) ||
1111 ReallocatingMemFnMap.lookup(Call))
1114 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1117 const auto *Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1118 return Func && Func->
hasAttr<OwnershipAttr>();
1121std::optional<ProgramStateRef>
1143 if (!KernelZeroFlagVal) {
1144 if (
OS == llvm::Triple::FreeBSD)
1145 KernelZeroFlagVal = 0x0100;
1146 else if (
OS == llvm::Triple::NetBSD)
1147 KernelZeroFlagVal = 0x0002;
1148 else if (
OS == llvm::Triple::OpenBSD)
1149 KernelZeroFlagVal = 0x0008;
1150 else if (
OS == llvm::Triple::Linux)
1152 KernelZeroFlagVal = 0x8000;
1159 return std::nullopt;
1165 if (
Call.getNumArgs() < 2)
1166 return std::nullopt;
1168 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1169 const SVal V =
C.getSVal(FlagsEx);
1170 if (!isa<NonLoc>(
V)) {
1173 return std::nullopt;
1177 NonLoc ZeroFlag =
C.getSValBuilder()
1178 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1180 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1184 return std::nullopt;
1189 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1192 if (TrueState && !FalseState) {
1193 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1194 return MallocMemAux(
C, Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1198 return std::nullopt;
1202 const Expr *BlockBytes) {
1204 SVal BlocksVal =
C.getSVal(Blocks);
1205 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1207 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1212void MallocChecker::checkBasicAlloc(
const CallEvent &Call,
1217 State = ProcessZeroAllocCheck(Call, 0, State);
1218 C.addTransition(State);
1221void MallocChecker::checkKernelMalloc(
const CallEvent &Call,
1224 std::optional<ProgramStateRef> MaybeState =
1225 performKernelMalloc(Call,
C, State);
1227 State = *MaybeState;
1231 C.addTransition(State);
1235 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());
1239 if (isa<CXXMethodDecl>(FD))
1249 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());
1253 if (isa<CXXMethodDecl>(FD))
1263 bool ShouldFreeOnFail)
const {
1273 State = ReallocMemAux(
C, Call, ShouldFreeOnFail, State, AF_Malloc);
1274 State = ProcessZeroAllocCheck(Call, 1, State);
1275 C.addTransition(State);
1278void MallocChecker::checkCalloc(
const CallEvent &Call,
1281 State = CallocMem(
C, Call, State);
1282 State = ProcessZeroAllocCheck(Call, 0, State);
1283 State = ProcessZeroAllocCheck(Call, 1, State);
1284 C.addTransition(State);
1289 bool IsKnownToBeAllocatedMemory =
false;
1290 if (suppressDeallocationsInSuspiciousContexts(Call,
C))
1292 State = FreeMemAux(
C, Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1294 C.addTransition(State);
1297void MallocChecker::checkAlloca(
const CallEvent &Call,
1302 State = ProcessZeroAllocCheck(Call, 0, State);
1303 C.addTransition(State);
1306void MallocChecker::checkStrdup(
const CallEvent &Call,
1309 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1314 C.addTransition(State);
1317void MallocChecker::checkIfNameIndex(
const CallEvent &Call,
1325 C.addTransition(State);
1328void MallocChecker::checkIfFreeNameIndex(
const CallEvent &Call,
1331 bool IsKnownToBeAllocatedMemory =
false;
1332 State = FreeMemAux(
C, Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1334 C.addTransition(State);
1337void MallocChecker::checkCXXNewOrCXXDelete(
const CallEvent &Call,
1340 bool IsKnownToBeAllocatedMemory =
false;
1341 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1355 MallocMemAux(
C, Call, CE->getArg(0),
UndefinedVal(), State, AF_CXXNew);
1356 State = ProcessZeroAllocCheck(Call, 0, State);
1359 State = MallocMemAux(
C, Call, CE->getArg(0),
UndefinedVal(), State,
1361 State = ProcessZeroAllocCheck(Call, 0, State);
1364 State = FreeMemAux(
C, Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1367 case OO_Array_Delete:
1368 State = FreeMemAux(
C, Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1372 llvm_unreachable(
"not a new/delete operator");
1375 C.addTransition(State);
1378void MallocChecker::checkGMalloc0(
const CallEvent &Call,
1383 State = MallocMemAux(
C, Call,
Call.getArgExpr(0), zeroVal, State, AF_Malloc);
1384 State = ProcessZeroAllocCheck(Call, 0, State);
1385 C.addTransition(State);
1388void MallocChecker::checkGMemdup(
const CallEvent &Call,
1392 MallocMemAux(
C, Call,
Call.getArgExpr(1),
UnknownVal(), State, AF_Malloc);
1393 State = ProcessZeroAllocCheck(Call, 1, State);
1394 C.addTransition(State);
1397void MallocChecker::checkGMallocN(
const CallEvent &Call,
1401 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1402 State = MallocMemAux(
C, Call, TotalSize, Init, State, AF_Malloc);
1403 State = ProcessZeroAllocCheck(Call, 0, State);
1404 State = ProcessZeroAllocCheck(Call, 1, State);
1405 C.addTransition(State);
1408void MallocChecker::checkGMallocN0(
const CallEvent &Call,
1413 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1414 State = MallocMemAux(
C, Call, TotalSize, Init, State, AF_Malloc);
1415 State = ProcessZeroAllocCheck(Call, 0, State);
1416 State = ProcessZeroAllocCheck(Call, 1, State);
1417 C.addTransition(State);
1420void MallocChecker::checkReallocN(
const CallEvent &Call,
1423 State = ReallocMemAux(
C, Call,
false, State, AF_Malloc,
1425 State = ProcessZeroAllocCheck(Call, 1, State);
1426 State = ProcessZeroAllocCheck(Call, 2, State);
1427 C.addTransition(State);
1430void MallocChecker::checkOwnershipAttr(
const CallEvent &Call,
1433 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1439 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1440 ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1445 switch (I->getOwnKind()) {
1446 case OwnershipAttr::Returns:
1447 State = MallocMemReturnsAttr(
C, Call, I, State);
1449 case OwnershipAttr::Takes:
1450 case OwnershipAttr::Holds:
1451 State = FreeMemAttr(
C, Call, I, State);
1456 C.addTransition(State);
1459void MallocChecker::checkPostCall(
const CallEvent &Call,
1463 if (!
Call.getOriginExpr())
1468 if (
const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) {
1469 (*Callback)(
this,
Call,
C);
1473 if (
const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) {
1474 (*Callback)(
this,
Call,
C);
1478 if (
const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) {
1479 (*Callback)(
this,
Call,
C);
1484 checkCXXNewOrCXXDelete(Call,
C);
1488 checkOwnershipAttr(Call,
C);
1494 std::optional<SVal> RetVal) {
1499 RetVal =
Call.getReturnValue();
1501 const Expr *Arg =
nullptr;
1503 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1504 Arg = CE->getArg(IndexOfSizeArg);
1506 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1507 if (
NE->isArray()) {
1508 Arg = *
NE->getArraySize();
1513 llvm_unreachable(
"not a CallExpr or CXXNewExpr");
1525 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1529 std::tie(TrueState, FalseState) =
1530 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal, Zero));
1532 if (TrueState && !FalseState) {
1533 SymbolRef Sym = RetVal->getAsLocSymbol();
1537 const RefState *RS = State->get<RegionState>(Sym);
1539 if (RS->isAllocated())
1540 return TrueState->set<RegionState>(Sym,
1541 RefState::getAllocatedOfSizeZero(RS));
1549 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1560 while (!PointeeType.isNull()) {
1561 Result = PointeeType;
1562 PointeeType = PointeeType->getPointeeType();
1575 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1581 for (
const auto *CtorParam : CtorD->
parameters()) {
1584 if (CtorParamPointeeT.
isNull())
1599 AllocationFamily Family)
const {
1604 const ParentMap &PM =
C.getLocationContext()->getParentMap();
1620 State = ProcessZeroAllocCheck(Call, 0, State, Target);
1626 if (!
C.wasInlined) {
1629 (
Call.getOriginExpr()->isArray() ? AF_CXXNewArray : AF_CXXNew));
1630 C.addTransition(State);
1640 StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
1641 return FirstSlot ==
"dataWithBytesNoCopy" ||
1642 FirstSlot ==
"initWithBytesNoCopy" ||
1643 FirstSlot ==
"initWithCharactersNoCopy";
1650 for (
unsigned i = 1; i < S.getNumArgs(); ++i)
1651 if (S.getNameForSlot(i).equals(
"freeWhenDone"))
1652 return !Call.getArgSVal(i).isZeroConstant();
1654 return std::nullopt;
1657void MallocChecker::checkPostObjCMessage(
const ObjCMethodCall &Call,
1669 if (
Call.hasNonZeroCallbackArg())
1672 bool IsKnownToBeAllocatedMemory;
1674 FreeMemAux(
C,
Call.getArgExpr(0), Call,
C.getState(),
1675 true, IsKnownToBeAllocatedMemory, AF_Malloc,
1678 C.addTransition(State);
1683 const OwnershipAttr *Att,
1688 if (Att->getModule()->getName() !=
"malloc")
1691 OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
1693 return MallocMemAux(
C, Call,
Call.getArgExpr(I->getASTIndex()),
1703 AllocationFamily Family) {
1708 return MallocMemAux(
C, Call,
C.getSVal(SizeEx), Init, State, Family);
1714 AllocationFamily Family) {
1718 const Expr *CE =
Call.getOriginExpr();
1727 unsigned Count =
C.blockCount();
1732 State = State->BindExpr(CE,
C.getLocationContext(), RetVal);
1735 State = State->bindDefaultInitial(RetVal, Init, LCtx);
1750 AllocationFamily Family,
1751 std::optional<SVal> RetVal) {
1757 RetVal =
C.getSVal(E);
1760 if (!RetVal->getAs<
Loc>())
1763 SymbolRef Sym = RetVal->getAsLocSymbol();
1769 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
1774 const OwnershipAttr *Att,
1779 if (Att->getModule()->getName() !=
"malloc")
1782 bool IsKnownToBeAllocated =
false;
1784 for (
const auto &Arg : Att->args()) {
1786 FreeMemAux(
C, Call, State, Arg.getASTIndex(),
1787 Att->getOwnKind() == OwnershipAttr::Holds,
1788 IsKnownToBeAllocated, AF_Malloc);
1798 bool Hold,
bool &IsKnownToBeAllocated,
1799 AllocationFamily Family,
1800 bool ReturnsNullOnFailure)
const {
1804 if (
Call.getNumArgs() < (Num + 1))
1807 return FreeMemAux(
C,
Call.getArgExpr(Num), Call, State, Hold,
1808 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
1815 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
1817 assert(*Ret &&
"We should not store the null return symbol");
1820 RetStatusSymbol = *Ret;
1827 if (
const CallExpr *CE = dyn_cast<CallExpr>(E)) {
1840 if (Msg->isInstanceMessage())
1844 Msg->getSelector().
print(os);
1848 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
1868 case AF_Malloc: os <<
"malloc()";
return;
1869 case AF_CXXNew: os <<
"'new'";
return;
1870 case AF_CXXNewArray: os <<
"'new[]'";
return;
1871 case AF_IfNameIndex: os <<
"'if_nameindex()'";
return;
1872 case AF_InnerBuffer: os <<
"container-specific allocator";
return;
1874 case AF_None: llvm_unreachable(
"not a deallocation expression");
1880 case AF_Malloc: os <<
"free()";
return;
1881 case AF_CXXNew: os <<
"'delete'";
return;
1882 case AF_CXXNewArray: os <<
"'delete[]'";
return;
1883 case AF_IfNameIndex: os <<
"'if_freenameindex()'";
return;
1884 case AF_InnerBuffer: os <<
"container-specific deallocator";
return;
1886 case AF_None: llvm_unreachable(
"suspicious argument");
1893 AllocationFamily Family,
bool ReturnsNullOnFailure)
const {
1898 SVal ArgVal =
C.getSVal(ArgExpr);
1899 if (!isa<DefinedOrUnknownSVal>(ArgVal))
1904 if (!isa<Loc>(location))
1909 std::tie(notNullState, nullState) = State->assume(location);
1910 if (nullState && !notNullState)
1919 const Expr *ParentExpr =
Call.getOriginExpr();
1938 if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
1939 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
1947 if (isa<BlockDataRegion>(R)) {
1948 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
1957 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
1966 if (isa<AllocaRegion>(R))
1969 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
1982 const RefState *RsBase = State->get<RegionState>(SymBase);
1983 SymbolRef PreviousRetStatusSymbol =
nullptr;
1985 IsKnownToBeAllocated =
1986 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
1991 if (RsBase->getAllocationFamily() == AF_Alloca) {
1997 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
1999 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2000 SymBase, PreviousRetStatusSymbol);
2005 }
else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2006 RsBase->isEscaped()) {
2009 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2010 if (!DeallocMatchesAlloc) {
2012 RsBase, SymBase, Hold);
2020 !
Offset.hasSymbolicOffset() &&
2021 Offset.getOffset() != 0) {
2022 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2031 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2037 State = State->remove<FreeReturnValue>(SymBase);
2041 if (ReturnsNullOnFailure) {
2042 SVal RetVal =
C.getSVal(ParentExpr);
2044 if (RetStatusSymbol) {
2045 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2046 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2054 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2058 return State->set<RegionState>(SymBase,
2059 RefState::getRelinquished(Family,
2062 return State->set<RegionState>(SymBase,
2063 RefState::getReleased(Family, ParentExpr));
2066std::optional<MallocChecker::CheckKind>
2067MallocChecker::getCheckIfTracked(AllocationFamily Family,
2068 bool IsALeakCheck)
const {
2072 case AF_IfNameIndex: {
2073 if (ChecksEnabled[CK_MallocChecker])
2074 return CK_MallocChecker;
2075 return std::nullopt;
2078 case AF_CXXNewArray: {
2080 if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2081 return CK_NewDeleteLeaksChecker;
2084 if (ChecksEnabled[CK_NewDeleteChecker])
2085 return CK_NewDeleteChecker;
2087 return std::nullopt;
2089 case AF_InnerBuffer: {
2090 if (ChecksEnabled[CK_InnerPointerChecker])
2091 return CK_InnerPointerChecker;
2092 return std::nullopt;
2095 llvm_unreachable(
"no family");
2098 llvm_unreachable(
"unhandled family");
2101std::optional<MallocChecker::CheckKind>
2103 bool IsALeakCheck)
const {
2104 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2105 return CK_MallocChecker;
2107 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2109 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2112bool MallocChecker::SummarizeValue(raw_ostream &os,
SVal V) {
2113 if (std::optional<nonloc::ConcreteInt> IntVal =
2115 os <<
"an integer (" << IntVal->getValue() <<
")";
2116 else if (std::optional<loc::ConcreteInt> ConstAddr =
2118 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2120 os <<
"the address of the label '" <<
Label->getLabel()->getName() <<
"'";
2127bool MallocChecker::SummarizeRegion(raw_ostream &os,
2130 case MemRegion::FunctionCodeRegionKind: {
2131 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2133 os <<
"the address of the function '" << *FD <<
'\'';
2135 os <<
"the address of a function";
2138 case MemRegion::BlockCodeRegionKind:
2141 case MemRegion::BlockDataRegionKind:
2148 if (isa<StackLocalsSpaceRegion>(MS)) {
2149 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2157 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2159 os <<
"the address of a local stack variable";
2163 if (isa<StackArgumentsSpaceRegion>(MS)) {
2164 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2172 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2174 os <<
"the address of a parameter";
2178 if (isa<GlobalsSpaceRegion>(MS)) {
2179 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2188 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2190 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2192 os <<
"the address of a global variable";
2203 const Expr *DeallocExpr,
2204 AllocationFamily Family)
const {
2206 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2211 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2216 if (!BT_BadFree[*CheckKind])
2217 BT_BadFree[*CheckKind].reset(
new BugType(
2221 llvm::raw_svector_ostream os(buf);
2224 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2225 MR = ER->getSuperRegion();
2227 os <<
"Argument to ";
2229 os <<
"deallocator";
2232 bool Summarized = MR ? SummarizeRegion(os, MR)
2233 : SummarizeValue(os, ArgVal);
2235 os <<
", which is not memory allocated by ";
2237 os <<
"not memory allocated by ";
2241 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2243 R->markInteresting(MR);
2245 C.emitReport(std::move(R));
2252 std::optional<MallocChecker::CheckKind> CheckKind;
2254 if (ChecksEnabled[CK_MallocChecker])
2255 CheckKind = CK_MallocChecker;
2256 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2257 CheckKind = CK_MismatchedDeallocatorChecker;
2264 if (!BT_FreeAlloca[*CheckKind])
2265 BT_FreeAlloca[*CheckKind].reset(
new BugType(
2268 auto R = std::make_unique<PathSensitiveBugReport>(
2269 *BT_FreeAlloca[*CheckKind],
2270 "Memory allocated by alloca() should not be deallocated", N);
2273 C.emitReport(std::move(R));
2279 const Expr *DeallocExpr,
2281 bool OwnershipTransferred)
const {
2283 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2289 if (!BT_MismatchedDealloc)
2290 BT_MismatchedDealloc.reset(
2291 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2295 llvm::raw_svector_ostream os(buf);
2297 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2299 llvm::raw_svector_ostream AllocOs(AllocBuf);
2301 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2303 if (OwnershipTransferred) {
2305 os << DeallocOs.str() <<
" cannot";
2309 os <<
" take ownership of memory";
2312 os <<
" allocated by " << AllocOs.str();
2316 os <<
" allocated by " << AllocOs.str();
2318 os <<
" should be deallocated by ";
2322 os <<
", not " << DeallocOs.str();
2325 auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2327 R->markInteresting(Sym);
2329 R->addVisitor<MallocBugVisitor>(Sym);
2330 C.emitReport(std::move(R));
2336 AllocationFamily Family,
2337 const Expr *AllocExpr)
const {
2339 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2344 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2352 if (!BT_OffsetFree[*CheckKind])
2353 BT_OffsetFree[*CheckKind].reset(
new BugType(
2357 llvm::raw_svector_ostream os(buf);
2359 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2362 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2365 assert((
Offset.isValid() &&
2366 !
Offset.hasSymbolicOffset() &&
2367 Offset.getOffset() != 0) &&
2368 "Only symbols with a valid offset can have offset free errors");
2370 int offsetBytes =
Offset.getOffset() /
C.getASTContext().getCharWidth();
2372 os <<
"Argument to ";
2374 os <<
"deallocator";
2375 os <<
" is offset by "
2378 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2379 <<
" from the start of ";
2381 os <<
"memory allocated by " << AllocNameOs.str();
2383 os <<
"allocated memory";
2385 auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2389 C.emitReport(std::move(R));
2395 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2396 !ChecksEnabled[CK_InnerPointerChecker]) {
2401 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2406 if (!BT_UseFree[*CheckKind])
2407 BT_UseFree[*CheckKind].reset(
new BugType(
2410 AllocationFamily AF =
2411 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2413 auto R = std::make_unique<PathSensitiveBugReport>(
2414 *BT_UseFree[*CheckKind],
2415 AF == AF_InnerBuffer
2416 ?
"Inner pointer of container used after re/deallocation"
2417 :
"Use of memory after it is freed",
2420 R->markInteresting(Sym);
2422 R->addVisitor<MallocBugVisitor>(Sym);
2424 if (AF == AF_InnerBuffer)
2427 C.emitReport(std::move(R));
2435 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2440 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2445 if (!BT_DoubleFree[*CheckKind])
2446 BT_DoubleFree[*CheckKind].reset(
new BugType(
2449 auto R = std::make_unique<PathSensitiveBugReport>(
2450 *BT_DoubleFree[*CheckKind],
2451 (Released ?
"Attempt to free released memory"
2452 :
"Attempt to free non-owned memory"),
2455 R->markInteresting(Sym);
2457 R->markInteresting(PrevSym);
2458 R->addVisitor<MallocBugVisitor>(Sym);
2459 C.emitReport(std::move(R));
2465 if (!ChecksEnabled[CK_NewDeleteChecker]) {
2470 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2475 if (!BT_DoubleDelete)
2476 BT_DoubleDelete.reset(
new BugType(CheckNames[CK_NewDeleteChecker],
2480 auto R = std::make_unique<PathSensitiveBugReport>(
2481 *BT_DoubleDelete,
"Attempt to delete released memory", N);
2483 R->markInteresting(Sym);
2484 R->addVisitor<MallocBugVisitor>(Sym);
2485 C.emitReport(std::move(R));
2492 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2497 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2503 if (!BT_UseZerroAllocated[*CheckKind])
2504 BT_UseZerroAllocated[*CheckKind].reset(
2505 new BugType(CheckNames[*CheckKind],
"Use of zero allocated",
2508 auto R = std::make_unique<PathSensitiveBugReport>(
2509 *BT_UseZerroAllocated[*CheckKind],
2510 "Use of memory allocated with size zero", N);
2514 R->markInteresting(Sym);
2515 R->addVisitor<MallocBugVisitor>(Sym);
2517 C.emitReport(std::move(R));
2523 const Expr *FreeExpr,
2524 AllocationFamily Family)
const {
2525 if (!ChecksEnabled[CK_MallocChecker]) {
2530 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2535 if (!BT_BadFree[*CheckKind])
2536 BT_BadFree[*CheckKind].reset(
new BugType(
2540 llvm::raw_svector_ostream Os(Buf);
2543 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2544 MR = ER->getSuperRegion();
2546 Os <<
"Argument to ";
2548 Os <<
"deallocator";
2550 Os <<
" is a function pointer";
2552 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2554 R->markInteresting(MR);
2556 C.emitReport(std::move(R));
2563 AllocationFamily Family,
bool SuffixWithN)
const {
2567 const CallExpr *CE = cast<CallExpr>(
Call.getOriginExpr());
2575 SVal Arg0Val =
C.getSVal(arg0Expr);
2576 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2583 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2589 SVal TotalSize =
C.getSVal(Arg1);
2591 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2592 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2598 svalBuilder.makeIntValWithWidth(
2599 svalBuilder.getContext().getSizeType(), 0));
2602 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2604 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2607 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2608 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2612 if (PrtIsNull && !SizeIsZero) {
2614 C, Call, TotalSize,
UndefinedVal(), StatePtrIsNull, Family);
2618 if (PrtIsNull && SizeIsZero)
2623 bool IsKnownToBeAllocated =
false;
2632 C, Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2637 FreeMemAux(
C, Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2640 MallocMemAux(
C, Call, TotalSize,
UnknownVal(), stateFree, Family);
2644 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2645 if (ShouldFreeOnFail)
2646 Kind = OAR_FreeOnFailure;
2647 else if (!IsKnownToBeAllocated)
2648 Kind = OAR_DoNotTrackAfterFailure;
2652 SVal RetVal =
C.getSVal(CE);
2654 assert(FromPtr && ToPtr &&
2655 "By this point, FreeMemAux and MallocMemAux should have checked "
2656 "whether the argument or the return value is symbolic!");
2660 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2661 ReallocPair(FromPtr, Kind));
2663 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2664 return stateRealloc;
2675 if (
Call.getNumArgs() < 2)
2681 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2683 return MallocMemAux(
C, Call, TotalSize, zeroVal, State, AF_Malloc);
2686MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2693 const MemRegion *ReferenceRegion =
nullptr;
2697 if (!State->get<RegionState>(Sym))
2702 if (!ReferenceRegion) {
2703 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
2704 SVal Val = State->getSVal(MR);
2710 ReferenceRegion = MR;
2718 if (NContext == LeakContext ||
2724 return LeakInfo(AllocNode, ReferenceRegion);
2730 if (!ChecksEnabled[CK_MallocChecker] &&
2731 !ChecksEnabled[CK_NewDeleteLeaksChecker])
2734 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2735 assert(RS &&
"cannot leak an untracked symbol");
2736 AllocationFamily Family = RS->getAllocationFamily();
2738 if (Family == AF_Alloca)
2741 std::optional<MallocChecker::CheckKind> CheckKind =
2742 getCheckIfTracked(Family,
true);
2748 if (!BT_Leak[*CheckKind]) {
2754 BT_Leak[*CheckKind].reset(
new BugType(CheckNames[*CheckKind],
"Memory leak",
2765 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
2770 C.getSourceManager(),
2774 llvm::raw_svector_ostream os(buf);
2776 os <<
"Potential leak of memory pointed to by ";
2779 os <<
"Potential memory leak";
2782 auto R = std::make_unique<PathSensitiveBugReport>(
2783 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
2785 R->markInteresting(Sym);
2786 R->addVisitor<MallocBugVisitor>(Sym,
true);
2787 if (ShouldRegisterNoOwnershipChangeVisitor)
2788 R->addVisitor<NoOwnershipChangeVisitor>(Sym,
this);
2789 C.emitReport(std::move(R));
2792void MallocChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
2796 RegionStateTy OldRS = state->get<RegionState>();
2797 RegionStateTy::Factory &F = state->get_context<RegionState>();
2799 RegionStateTy RS = OldRS;
2801 for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
2802 if (SymReaper.
isDead(I->first)) {
2803 if (I->second.isAllocated() || I->second.isAllocatedOfSizeZero())
2804 Errors.push_back(I->first);
2806 RS = F.remove(RS, I->first);
2812 assert(state->get<ReallocPairs>() ==
2813 C.getState()->get<ReallocPairs>());
2814 assert(state->get<FreeReturnValue>() ==
2815 C.getState()->get<FreeReturnValue>());
2820 ReallocPairsTy RP = state->get<ReallocPairs>();
2821 for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
2822 if (SymReaper.
isDead(I->first) ||
2823 SymReaper.
isDead(I->second.ReallocatedSym)) {
2824 state = state->remove<ReallocPairs>(I->first);
2829 FreeReturnValueTy FR = state->get<FreeReturnValue>();
2830 for (FreeReturnValueTy::iterator I = FR.begin(), E = FR.end(); I != E; ++I) {
2831 if (SymReaper.
isDead(I->first) ||
2832 SymReaper.
isDead(I->second)) {
2833 state = state->remove<FreeReturnValue>(I->first);
2839 if (!Errors.empty()) {
2841 N =
C.generateNonFatalErrorNode(
C.getState(), &Tag);
2844 I = Errors.begin(), E = Errors.end(); I != E; ++I) {
2845 HandleLeak(*I, N,
C);
2850 C.addTransition(state->set<RegionState>(RS), N);
2853void MallocChecker::checkPreCall(
const CallEvent &Call,
2856 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call)) {
2859 if (!ChecksEnabled[CK_NewDeleteChecker])
2867 bool IsKnownToBeAllocated;
2869 false, IsKnownToBeAllocated,
2870 (DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
2872 C.addTransition(State);
2876 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&Call)) {
2877 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
2878 if (!Sym || checkDoubleDelete(Sym,
C))
2888 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(Call))
2894 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
2895 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
2900 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
2902 if (isa<Loc>(ArgSVal)) {
2906 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
2912void MallocChecker::checkPreStmt(
const ReturnStmt *S,
2914 checkEscapeOnReturn(S,
C);
2920void MallocChecker::checkEndFunction(
const ReturnStmt *S,
2922 checkEscapeOnReturn(S,
C);
2925void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
2930 const Expr *E = S->getRetValue();
2936 SVal RetVal =
C.getSVal(E);
2943 if (isa<FieldRegion, ElementRegion>(MR))
2946 Sym = BMR->getSymbol();
2950 checkUseAfterFree(Sym,
C, E);
2956void MallocChecker::checkPostStmt(
const BlockExpr *BE,
2966 cast<BlockDataRegion>(
C.getSVal(BE).getAsRegion());
2978 for ( ; I != E; ++I) {
2983 Regions.push_back(VR);
2987 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
2988 C.addTransition(state);
2993 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2994 return (RS && RS->isReleased());
2997bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
2999 if (
Call.getNumArgs() == 0)
3002 StringRef FunctionStr =
"";
3003 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3005 if (Body->getBeginLoc().isValid())
3009 C.getSourceManager(),
C.getLangOpts());
3012 if (!FunctionStr.contains(
"__isl_"))
3017 for (
const Expr *Arg : cast<CallExpr>(
Call.getOriginExpr())->arguments())
3018 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3019 if (
const RefState *RS = State->get<RegionState>(Sym))
3020 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3022 C.addTransition(State);
3027 const Stmt *S)
const {
3030 HandleUseAfterFree(
C, S->getSourceRange(), Sym);
3038 const Stmt *S)
const {
3041 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3042 if (RS->isAllocatedOfSizeZero())
3043 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3045 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3046 HandleUseZeroAlloc(
C, S->getSourceRange(), Sym);
3053 HandleDoubleDelete(
C, Sym);
3060void MallocChecker::checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
3064 checkUseAfterFree(Sym,
C, S);
3065 checkUseZeroAllocated(Sym,
C, S);
3073 bool Assumption)
const {
3074 RegionStateTy RS = state->get<RegionState>();
3075 for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
3080 state = state->remove<RegionState>(I.getKey());
3085 ReallocPairsTy RP = state->get<ReallocPairs>();
3086 for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
3093 SymbolRef ReallocSym = I.getData().ReallocatedSym;
3094 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3095 if (RS->isReleased()) {
3096 switch (I.getData().Kind) {
3097 case OAR_ToBeFreedAfterFailure:
3098 state = state->set<RegionState>(ReallocSym,
3099 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3101 case OAR_DoNotTrackAfterFailure:
3102 state = state->remove<RegionState>(ReallocSym);
3105 assert(I.getData().Kind == OAR_FreeOnFailure);
3109 state = state->remove<ReallocPairs>(I.getKey());
3115bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3120 EscapingSymbol =
nullptr;
3126 if (!isa<SimpleFunctionCall, ObjCMethodCall>(Call))
3130 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {
3133 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3146 return *FreeWhenDone;
3152 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3153 if (FirstSlot.endswith(
"NoCopy"))
3160 if (FirstSlot.startswith(
"addPointer") ||
3161 FirstSlot.startswith(
"insertPointer") ||
3162 FirstSlot.startswith(
"replacePointer") ||
3163 FirstSlot.equals(
"valueWithPointer")) {
3170 if (Msg->getMethodFamily() ==
OMF_init) {
3171 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3181 const FunctionDecl *FD = cast<SimpleFunctionCall>(Call)->getDecl();
3187 if (isMemCall(*Call))
3191 if (!
Call->isInSystemHeader())
3198 StringRef FName = II->
getName();
3202 if (FName.endswith(
"NoCopy")) {
3206 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3207 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3208 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3209 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3210 if (DeallocatorName ==
"kCFAllocatorNull")
3221 if (FName ==
"funopen")
3222 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3228 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3229 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3230 if (
Call->getNumArgs() >= 1) {
3231 const Expr *ArgE =
Call->getArgExpr(0)->IgnoreParenCasts();
3232 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3233 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3234 if (D->getCanonicalDecl()->getName().contains(
"std"))
3244 if (FName ==
"CGBitmapContextCreate" ||
3245 FName ==
"CGBitmapContextCreateWithData" ||
3246 FName ==
"CVPixelBufferCreateWithBytes" ||
3247 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3248 FName ==
"OSAtomicEnqueue") {
3252 if (FName ==
"postEvent" &&
3257 if (FName ==
"connectImpl" &&
3266 if (
Call->argumentsMayEscape())
3278 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3287 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3292 return (RS->getAllocationFamily() == AF_CXXNewArray ||
3293 RS->getAllocationFamily() == AF_CXXNew);
3299 bool IsConstPointerEscape)
const {
3304 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
3310 for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
3315 if (EscapingSymbol && EscapingSymbol != sym)
3318 if (
const RefState *RS = State->get<RegionState>(sym))
3319 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3321 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3327 SVal ArgVal)
const {
3328 if (!KernelZeroSizePtrValue)
3329 KernelZeroSizePtrValue =
3332 const llvm::APSInt *ArgValKnown =
3333 C.getSValBuilder().getKnownValue(State, ArgVal);
3334 return ArgValKnown && *KernelZeroSizePtrValue &&
3335 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3340 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3341 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3343 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3345 if (!currMap.lookup(sym))
3355 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3356 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3357 N.contains_insensitive(
"intrusive") ||
3358 N.contains_insensitive(
"shared")) {
3372 const RefState *RSCurr = state->get<RegionState>(Sym);
3373 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3378 if (!S && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer))
3390 if (ReleaseDestructorLC) {
3391 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3393 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3394 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3395 if (ReleaseDestructorLC == CurrentLC ||
3396 ReleaseDestructorLC->
isParentOf(CurrentLC)) {
3408 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3410 llvm::raw_svector_ostream
OS(Buf);
3413 if (isAllocated(RSCurr, RSPrev, S)) {
3414 Msg =
"Memory is allocated";
3415 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3416 Sym,
"Returned allocated memory");
3418 const auto Family = RSCurr->getAllocationFamily();
3423 case AF_CXXNewArray:
3424 case AF_IfNameIndex:
3425 Msg =
"Memory is released";
3426 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3427 Sym,
"Returning; memory was released");
3429 case AF_InnerBuffer: {
3432 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
3434 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
3437 OS <<
"deallocated by call to destructor";
3438 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3439 Sym,
"Returning; inner buffer was deallocated");
3441 OS <<
"reallocated by call to '";
3442 const Stmt *S = RSCurr->getStmt();
3443 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3444 OS << MemCallE->getMethodDecl()->getDeclName();
3445 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3446 OS << OpCallE->getDirectCallee()->getDeclName();
3447 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
3450 CEMgr.getSimpleCall(CallE, state, CurrentLC, {
nullptr, 0});
3451 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
3452 OS << D->getDeclName();
3457 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3458 Sym,
"Returning; inner buffer was reallocated");
3464 llvm_unreachable(
"Unhandled allocation family!");
3470 bool FoundAnyDestructor =
false;
3472 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
3478 }
else if (!FoundAnyDestructor) {
3479 assert(!ReleaseDestructorLC &&
3480 "There can be only one release point!");
3492 FoundAnyDestructor =
true;
3496 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
3497 Msg =
"Memory ownership is transferred";
3498 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
3499 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3500 Mode = ReallocationFailed;
3501 Msg =
"Reallocation failed";
3502 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3503 Sym,
"Reallocation failed");
3507 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3508 "We only support one failed realloc at a time.");
3510 FailedReallocSymbol = sym;
3515 }
else if (Mode == ReallocationFailed) {
3516 assert(FailedReallocSymbol &&
"No symbol to look for.");
3519 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3521 Msg =
"Attempt to reallocate memory";
3522 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3523 Sym,
"Returned reallocated memory");
3524 FailedReallocSymbol =
nullptr;
3539 assert(RSCurr->getAllocationFamily() == AF_InnerBuffer);
3550 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
3555void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
3556 const char *NL,
const char *Sep)
const {
3558 RegionStateTy RS = State->get<RegionState>();
3560 if (!RS.isEmpty()) {
3561 Out << Sep <<
"MallocChecker :" << NL;
3562 for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
3563 const RefState *RefS = State->get<RegionState>(I.getKey());
3564 AllocationFamily Family = RefS->getAllocationFamily();
3565 std::optional<MallocChecker::CheckKind> CheckKind =
3566 getCheckIfTracked(Family);
3568 CheckKind = getCheckIfTracked(Family,
true);
3570 I.getKey()->dumpToStream(Out);
3572 I.getData().dump(Out);
3574 Out <<
" (" << CheckNames[*CheckKind].getName() <<
")";
3582namespace allocation_state {
3586 AllocationFamily Family = AF_InnerBuffer;
3587 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3597 MallocChecker *checker = mgr.
getChecker<MallocChecker>();
3598 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] =
true;
3599 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3605 checker->ShouldIncludeOwnershipAnnotatedFunctions =
3607 checker->ShouldRegisterNoOwnershipChangeVisitor =
3609 checker,
"AddNoOwnershipChangeNotes");
3612bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
3616#define REGISTER_CHECKER(name) \
3617 void ento::register##name(CheckerManager &mgr) { \
3618 MallocChecker *checker = mgr.getChecker<MallocChecker>(); \
3619 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
3620 checker->CheckNames[MallocChecker::CK_##name] = \
3621 mgr.getCurrentCheckerName(); \
3624 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
static CompilationDatabasePluginRegistry::Add< FixedCompilationDatabasePlugin > X("fixed-compilation-database", "Reads plain-text flags file")
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
#define REGISTER_CHECKER(name)
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
static QualType getDeepPointeeType(QualType T)
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)
Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
static bool isGRealloc(const CallEvent &Call)
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)
Print expected name of a deallocator based on the allocator's family.
static bool isStandardRealloc(const CallEvent &Call)
static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)
Checks if the previous call to free on the given symbol failed - if free failed, returns true.
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)
Update the RefState to reflect the new memory allocation.
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool isStandardNewDelete(const FunctionDecl *FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
__device__ __2f16 float bool s
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
CanQualType UnsignedLongTy
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Represents a C++ constructor within a class.
Represents a delete expression for memory deallocation and destructor calls, e.g.
Represents a C++ destructor within a class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Represents a point when we begin processing an inlined call.
const Stmt * getCallExpr() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
static CharSourceRange getTokenRange(SourceRange R)
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
SourceLocation getLocation() const
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
ArrayRef< ParmVarDecl * > parameters() const
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
QualType getDeclaredReturnType() const
Get the declared return type, which may differ from the actual return type if the return type is dedu...
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
This represents a decl that may have a name.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
An expression that sends a message to the given Objective-C object or class.
bool isConsumedExpr(Expr *E) const
Represents a program point just after an implicit call event.
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Smart pointer class that efficiently represents Objective-C method names.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
A trivial tuple used to represent a source range.
It represents a stack frame of the call stack (based on CallEvent).
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isFunctionPointerType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Maps string IDs to AST nodes matched by parts of a matcher.
Represents a call to any sort of function that might have a FunctionDecl.
LLVM_ATTRIBUTE_RETURNS_NONNULL const VarRegion * getCapturedRegion() const
BlockDataRegion - A region that represents a block instance.
referenced_vars_iterator referenced_vars_begin() const
referenced_vars_iterator referenced_vars_end() 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)
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 QualType getType() const =0
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
virtual bool VisitSymbol(SymbolRef sym)=0
A visitor method invoked by ProgramStateManager::scanReachableSymbols.
SymbolicRegion - A special, "non-concrete" region.
SymbolRef getSymbol() const
It might return null.
TypedRegion - An abstract class representing regions that are typed.
const VarDecl * getDecl() const override=0
const StackFrameContext * getStackFrame() const
It might return null.
Value representing integer constant.
Defines the clang::TargetInfo interface.
__inline void unsigned int _2
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDeleteExpr > cxxDeleteExpr
Matches delete expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)
This function provides an additional visitor that augments the bug report with information relevant t...
const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)
'Sym' represents a pointer to the inner buffer of a container object.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
const char *const MemoryError
@ CDF_MaybeBuiltin
Describes a C standard function that is sometimes implemented as a macro that expands to a compiler b...
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent, SValBuilder &SVB)
Set the dynamic extent Extent of the region MR.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool NE(InterpState &S, CodePtr OpPC)
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
bool Zero(InterpState &S, CodePtr OpPC)
bool Call(InterpState &S, CodePtr &PC, const Function *Func)
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
@ C
Languages that the frontend can parse and compile.
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.