81#include "llvm/ADT/STLExtras.h"
82#include "llvm/ADT/SetOperations.h"
83#include "llvm/ADT/StringExtras.h"
84#include "llvm/Support/Casting.h"
85#include "llvm/Support/Compiler.h"
86#include "llvm/Support/ErrorHandling.h"
87#include "llvm/Support/raw_ostream.h"
94using namespace std::placeholders;
106enum AllocationFamilyKind {
117struct AllocationFamily {
118 AllocationFamilyKind
Kind;
119 std::optional<StringRef> CustomName;
121 explicit AllocationFamily(AllocationFamilyKind AKind,
122 std::optional<StringRef> Name = std::nullopt)
123 :
Kind(AKind), CustomName(Name) {
124 assert((Kind != AF_Custom || CustomName.has_value()) &&
125 "Custom family must specify also the name");
128 if (Kind == AF_Custom && CustomName.value() ==
"malloc") {
130 CustomName = std::nullopt;
135 return std::tie(Kind, CustomName) == std::tie(
Other.Kind,
Other.CustomName);
139 return !(*
this ==
Other);
142 void Profile(llvm::FoldingSetNodeID &ID)
const {
145 if (Kind == AF_Custom)
146 ID.AddString(CustomName.value());
191 AllocationFamily Family;
193 RefState(Kind k,
const Stmt *
s, AllocationFamily family)
194 : S(
s), K(k), Family(family) {
195 assert(family.Kind != AF_None);
199 bool isAllocated()
const {
return K == Allocated; }
200 bool isAllocatedOfSizeZero()
const {
return K == AllocatedOfSizeZero; }
201 bool isReleased()
const {
return K == Released; }
202 bool isRelinquished()
const {
return K == Relinquished; }
203 bool isEscaped()
const {
return K == Escaped; }
204 AllocationFamily getAllocationFamily()
const {
return Family; }
205 const Stmt *getStmt()
const {
return S; }
208 return K ==
X.K && S ==
X.S && Family ==
X.Family;
211 static RefState getAllocated(AllocationFamily family,
const Stmt *
s) {
212 return RefState(Allocated,
s, family);
214 static RefState getAllocatedOfSizeZero(
const RefState *RS) {
215 return RefState(AllocatedOfSizeZero, RS->getStmt(),
216 RS->getAllocationFamily());
218 static RefState getReleased(AllocationFamily family,
const Stmt *
s) {
219 return RefState(Released,
s, family);
221 static RefState getRelinquished(AllocationFamily family,
const Stmt *
s) {
222 return RefState(Relinquished,
s, family);
224 static RefState getEscaped(
const RefState *RS) {
225 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
228 void Profile(llvm::FoldingSetNodeID &ID)
const {
234 LLVM_DUMP_METHOD
void dump(raw_ostream &OS)
const {
236#define CASE(ID) case ID: OS << #ID; break;
238 CASE(AllocatedOfSizeZero)
245 LLVM_DUMP_METHOD
void dump()
const {
dump(llvm::errs()); }
260 AllocationFamily Family,
261 std::optional<SVal> RetVal = std::nullopt);
275enum OwnershipAfterReallocKind {
277 OAR_ToBeFreedAfterFailure,
287 OAR_DoNotTrackAfterFailure
300 OwnershipAfterReallocKind
Kind;
302 ReallocPair(
SymbolRef S, OwnershipAfterReallocKind K)
303 : ReallocatedSym(S),
Kind(K) {}
304 void Profile(llvm::FoldingSetNodeID &ID)
const {
306 ID.AddPointer(ReallocatedSym);
309 return ReallocatedSym ==
X.ReallocatedSym &&
322 if (!
Call.getDecl() || !isa<FunctionDecl>(
Call.getDecl()))
334 :
public Checker<check::DeadSymbols, check::PointerEscape,
335 check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
336 check::EndFunction, check::PreCall, check::PostCall,
337 check::NewAllocator, check::PostStmt<BlockExpr>,
338 check::PostObjCMessage, check::Location, eval::Assume> {
344 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
346 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
356 CK_NewDeleteLeaksChecker,
357 CK_MismatchedDeallocatorChecker,
358 CK_InnerPointerChecker,
359 CK_TaintedAllocChecker,
363 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
365 bool ChecksEnabled[CK_NumCheckKinds] = {
false};
377 bool Assumption)
const;
378 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
391 const char *NL,
const char *Sep)
const override;
394 mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];
395 mutable std::unique_ptr<BugType> BT_DoubleDelete;
396 mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];
397 mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];
398 mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
399 mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
400 mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
401 mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
402 mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
403 mutable std::unique_ptr<BugType> BT_TaintedAlloc;
405#define CHECK_FN(NAME) \
406 void NAME(const CallEvent &Call, CheckerContext &C) const;
427 bool ShouldFreeOnFail)
const;
429 using CheckFn = std::function<void(
const MallocChecker *,
435 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetdelim},
436 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetdelim},
440 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
441 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
442 &MallocChecker::checkIfFreeNameIndex},
443 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
444 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
450 friend class NoMemOwnershipChangeVisitor;
453 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
454 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
458 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
459 &MallocChecker::checkAlloca},
460 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
461 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
462 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
463 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
464 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
465 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
466 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
467 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
468 {{CDM::CLibrary, {
"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
469 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
470 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
471 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
472 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
473 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
474 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
475 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
476 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
477 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
478 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
479 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
483 {{CDM::CLibrary, {
"realloc"}, 2},
484 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
485 {{CDM::CLibrary, {
"reallocf"}, 2},
486 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
true)},
487 {{CDM::CLibrary, {
"g_realloc"}, 2},
488 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
489 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
490 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
491 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
492 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
496 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetdelim},
497 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::checkGetdelim},
503 AllocationFamily Family)
const;
507 AllocationFamily Family)
const;
510 mutable std::optional<uint64_t> KernelZeroFlagVal;
512 using KernelZeroSizePtrValueTy = std::optional<int>;
517 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
523 AllocationFamily Family)
const;
534 ProcessZeroAllocCheck(
const CallEvent &
Call,
const unsigned IndexOfSizeArg,
536 std::optional<SVal> RetVal = std::nullopt);
583 AllocationFamily Family)
const;
587 [[nodiscard]] std::optional<ProgramStateRef>
610 const OwnershipAttr *Att,
634 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
635 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
661 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
662 std::optional<SVal> ArgValOpt = {})
const;
680 bool SuffixWithN =
false)
const;
689 const Expr *BlockBytes);
702 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
711 const Stmt *S)
const;
726 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
735 bool IsConstPointerEscape)
const;
744 std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
745 bool IsALeakCheck =
false)
const;
748 bool IsALeakCheck =
false)
const;
750 static bool SummarizeValue(raw_ostream &os,
SVal V);
751 static bool SummarizeRegion(raw_ostream &os,
const MemRegion *MR);
754 const Expr *DeallocExpr,
755 AllocationFamily Family)
const;
761 const Expr *DeallocExpr,
const RefState *RS,
762 SymbolRef Sym,
bool OwnershipTransferred)
const;
765 const Expr *DeallocExpr, AllocationFamily Family,
766 const Expr *AllocExpr =
nullptr)
const;
780 const Expr *FreeExpr,
781 AllocationFamily Family)
const;
810 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
811 const auto *MallocChk =
static_cast<const MallocChecker *
>(&
Checker);
812 if (MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
813 MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
816 if (
const auto *
Func =
817 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
818 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
825 return CallEnterState->get<RegionState>(Sym) !=
826 CallExitEndState->get<RegionState>(Sym);
833 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
835 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
854 if (
const auto *
Call = Match.getNodeAs<
CallExpr>(
"call"))
855 if (isFreeingCallAsWritten(*
Call))
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");
877 void Profile(llvm::FoldingSetNodeID &ID)
const override {
896 enum NotificationMode {
Normal, ReallocationFailed };
902 NotificationMode Mode;
914 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
915 : Sym(S), Mode(
Normal), FailedReallocSymbol(nullptr),
916 ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
918 static void *getTag() {
923 void Profile(llvm::FoldingSetNodeID &ID)
const override {
924 ID.AddPointer(getTag());
929 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
931 return (isa_and_nonnull<CallExpr, CXXNewExpr>(
Stmt) &&
933 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
935 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
940 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
943 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
944 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(
Stmt)) ||
945 (!
Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
950 static inline bool isRelinquished(
const RefState *RSCurr,
951 const RefState *RSPrev,
const Stmt *
Stmt) {
953 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(
Stmt) &&
954 (RSCurr && RSCurr->isRelinquished()) &&
955 (!RSPrev || !RSPrev->isRelinquished()));
962 static inline bool hasReallocFailed(
const RefState *RSCurr,
963 const RefState *RSPrev,
965 return ((!isa_and_nonnull<CallExpr>(
Stmt)) &&
967 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
969 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
984 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
989 class StackHintGeneratorForReallocationFailed
992 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
995 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1000 llvm::raw_svector_ostream os(buf);
1002 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1003 <<
" parameter failed";
1005 return std::string(os.str());
1009 return "Reallocation of returned value failed";
1028 state = state->remove<RegionState>(sym);
1039 if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete &&
1040 Kind != OO_Array_Delete)
1056 if (
Func->hasAttrs()) {
1057 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1058 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1059 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1066bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1067 if (FreeingMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1070 if (
const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl()))
1071 return isFreeingOwnershipAttrCall(
Func);
1077 if (FreeingMemFnMap.lookup(
Call) || AllocatingMemFnMap.lookup(
Call) ||
1078 ReallocatingMemFnMap.lookup(
Call))
1081 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1084 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1085 return Func &&
Func->hasAttr<OwnershipAttr>();
1088std::optional<ProgramStateRef>
1110 if (!KernelZeroFlagVal) {
1112 case llvm::Triple::FreeBSD:
1113 KernelZeroFlagVal = 0x0100;
1115 case llvm::Triple::NetBSD:
1116 KernelZeroFlagVal = 0x0002;
1118 case llvm::Triple::OpenBSD:
1119 KernelZeroFlagVal = 0x0008;
1121 case llvm::Triple::Linux:
1123 KernelZeroFlagVal = 0x8000;
1131 return std::nullopt;
1138 if (
Call.getNumArgs() < 2)
1139 return std::nullopt;
1141 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1142 const SVal V =
C.getSVal(FlagsEx);
1143 if (!isa<NonLoc>(
V)) {
1146 return std::nullopt;
1150 NonLoc ZeroFlag =
C.getSValBuilder()
1151 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1153 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1157 return std::nullopt;
1162 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1165 if (TrueState && !FalseState) {
1166 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1167 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1168 AllocationFamily(AF_Malloc));
1171 return std::nullopt;
1175 const Expr *BlockBytes) {
1177 SVal BlocksVal =
C.getSVal(Blocks);
1178 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1180 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1189 AllocationFamily(AF_Malloc));
1190 State = ProcessZeroAllocCheck(
Call, 0, State);
1191 C.addTransition(State);
1197 std::optional<ProgramStateRef> MaybeState =
1198 performKernelMalloc(
Call,
C, State);
1200 State = *MaybeState;
1203 AllocationFamily(AF_Malloc));
1204 C.addTransition(State);
1230 bool ShouldFreeOnFail)
const {
1240 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1241 AllocationFamily(AF_Malloc));
1242 State = ProcessZeroAllocCheck(
Call, 1, State);
1243 C.addTransition(State);
1249 State = CallocMem(
C,
Call, State);
1250 State = ProcessZeroAllocCheck(
Call, 0, State);
1251 State = ProcessZeroAllocCheck(
Call, 1, State);
1252 C.addTransition(State);
1257 bool IsKnownToBeAllocatedMemory =
false;
1258 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1260 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1261 AllocationFamily(AF_Malloc));
1262 C.addTransition(State);
1269 AllocationFamily(AF_Alloca));
1270 State = ProcessZeroAllocCheck(
Call, 0, State);
1271 C.addTransition(State);
1277 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1282 C.addTransition(State);
1291 AllocationFamily(AF_IfNameIndex));
1293 C.addTransition(State);
1296void MallocChecker::checkIfFreeNameIndex(
const CallEvent &
Call,
1299 bool IsKnownToBeAllocatedMemory =
false;
1300 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1301 AllocationFamily(AF_IfNameIndex));
1302 C.addTransition(State);
1305void MallocChecker::checkCXXNewOrCXXDelete(
const CallEvent &
Call,
1308 bool IsKnownToBeAllocatedMemory =
false;
1309 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1323 AllocationFamily(AF_CXXNew));
1324 State = ProcessZeroAllocCheck(
Call, 0, State);
1328 AllocationFamily(AF_CXXNewArray));
1329 State = ProcessZeroAllocCheck(
Call, 0, State);
1332 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1333 AllocationFamily(AF_CXXNew));
1335 case OO_Array_Delete:
1336 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1337 AllocationFamily(AF_CXXNewArray));
1340 assert(
false &&
"not a new/delete operator");
1344 C.addTransition(State);
1352 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1353 AllocationFamily(AF_Malloc));
1354 State = ProcessZeroAllocCheck(
Call, 0, State);
1355 C.addTransition(State);
1362 AllocationFamily(AF_Malloc));
1363 State = ProcessZeroAllocCheck(
Call, 1, State);
1364 C.addTransition(State);
1371 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1372 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1373 AllocationFamily(AF_Malloc));
1374 State = ProcessZeroAllocCheck(
Call, 0, State);
1375 State = ProcessZeroAllocCheck(
Call, 1, State);
1376 C.addTransition(State);
1384 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1385 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1386 AllocationFamily(AF_Malloc));
1387 State = ProcessZeroAllocCheck(
Call, 0, State);
1388 State = ProcessZeroAllocCheck(
Call, 1, State);
1389 C.addTransition(State);
1394 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1414 bool IsKnownToBeAllocated =
false;
1415 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1416 IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1419 C.addTransition(State);
1432 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1438 const auto LinePtr =
1442 if (!LinePtr || !Size || !LinePtr->getAsRegion())
1447 AllocationFamily(AF_Malloc), *LinePtr));
1453 State = ReallocMemAux(
C,
Call,
false, State,
1454 AllocationFamily(AF_Malloc),
1456 State = ProcessZeroAllocCheck(
Call, 1, State);
1457 State = ProcessZeroAllocCheck(
Call, 2, State);
1458 C.addTransition(State);
1461void MallocChecker::checkOwnershipAttr(
const CallEvent &
Call,
1464 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1470 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1471 ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1476 switch (I->getOwnKind()) {
1477 case OwnershipAttr::Returns:
1478 State = MallocMemReturnsAttr(
C,
Call, I, State);
1480 case OwnershipAttr::Takes:
1481 case OwnershipAttr::Holds:
1482 State = FreeMemAttr(
C,
Call, I, State);
1487 C.addTransition(State);
1494 if (!
Call.getOriginExpr())
1499 if (
const CheckFn *Callback = FreeingMemFnMap.lookup(
Call)) {
1500 (*Callback)(
this,
Call,
C);
1504 if (
const CheckFn *Callback = AllocatingMemFnMap.lookup(
Call)) {
1505 (*Callback)(
this,
Call,
C);
1509 if (
const CheckFn *Callback = ReallocatingMemFnMap.lookup(
Call)) {
1510 (*Callback)(
this,
Call,
C);
1515 checkCXXNewOrCXXDelete(
Call,
C);
1519 checkOwnershipAttr(
Call,
C);
1525 std::optional<SVal> RetVal) {
1530 RetVal =
Call.getReturnValue();
1532 const Expr *Arg =
nullptr;
1534 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1535 Arg = CE->
getArg(IndexOfSizeArg);
1537 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1538 if (
NE->isArray()) {
1539 Arg = *
NE->getArraySize();
1544 assert(
false &&
"not a CallExpr or CXXNewExpr");
1558 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1562 std::tie(TrueState, FalseState) =
1563 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal, Zero));
1565 if (TrueState && !FalseState) {
1566 SymbolRef Sym = RetVal->getAsLocSymbol();
1570 const RefState *RS = State->get<RegionState>(Sym);
1572 if (RS->isAllocated())
1573 return TrueState->set<RegionState>(Sym,
1574 RefState::getAllocatedOfSizeZero(RS));
1582 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1593 while (!PointeeType.isNull()) {
1594 Result = PointeeType;
1595 PointeeType = PointeeType->getPointeeType();
1608 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1614 for (
const auto *CtorParam : CtorD->
parameters()) {
1617 if (CtorParamPointeeT.
isNull())
1632 AllocationFamily Family)
const {
1637 const ParentMap &PM =
C.getLocationContext()->getParentMap();
1652 if (
Call.getOriginExpr()->isArray()) {
1653 if (
auto SizeEx =
NE->getArraySize())
1654 checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1655 AllocationFamily(AF_CXXNewArray));
1659 State = ProcessZeroAllocCheck(
Call, 0, State,
Target);
1665 if (!
C.wasInlined) {
1668 AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1670 C.addTransition(State);
1680 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1681 return FirstSlot ==
"dataWithBytesNoCopy" ||
1682 FirstSlot ==
"initWithBytesNoCopy" ||
1683 FirstSlot ==
"initWithCharactersNoCopy";
1690 for (
unsigned i = 1; i < S.getNumArgs(); ++i)
1691 if (S.getNameForSlot(i) ==
"freeWhenDone")
1692 return !
Call.getArgSVal(i).isZeroConstant();
1694 return std::nullopt;
1709 if (
Call.hasNonZeroCallbackArg())
1712 bool IsKnownToBeAllocatedMemory;
1714 true, IsKnownToBeAllocatedMemory,
1715 AllocationFamily(AF_Malloc),
1718 C.addTransition(State);
1723 const OwnershipAttr *Att,
1728 auto attrClassName = Att->getModule()->getName();
1729 auto Family = AllocationFamily(AF_Custom, attrClassName);
1731 if (!Att->args().empty()) {
1732 return MallocMemAux(
C,
Call,
1733 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1743 AllocationFamily Family)
const {
1748 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
1751void MallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRef State,
1754 AllocationFamily Family)
const {
1755 if (
ExplodedNode *N =
C.generateNonFatalErrorNode(State,
this)) {
1756 if (!BT_TaintedAlloc)
1757 BT_TaintedAlloc.reset(
new BugType(CheckNames[CK_TaintedAllocChecker],
1758 "Tainted Memory Allocation",
1760 auto R = std::make_unique<PathSensitiveBugReport>(*BT_TaintedAlloc, Msg, N);
1761 for (
auto TaintedSym : TaintedSyms) {
1762 R->markInteresting(TaintedSym);
1764 C.emitReport(std::move(R));
1770 AllocationFamily Family)
const {
1771 if (!ChecksEnabled[CK_TaintedAllocChecker])
1773 std::vector<SymbolRef> TaintedSyms =
1775 if (TaintedSyms.empty())
1784 const llvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
1787 std::optional<NonLoc> SizeNL = SizeSVal.
getAs<
NonLoc>();
1788 auto Cmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
1792 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
1793 if (!StateTooLarge && StateNotTooLarge) {
1798 std::string
Callee =
"Memory allocation function";
1799 if (
Call.getCalleeIdentifier())
1800 Callee =
Call.getCalleeIdentifier()->getName().str();
1802 Callee +
" is called with a tainted (potentially attacker controlled) "
1803 "value. Make sure the value is bound checked.",
1804 State,
C, TaintedSyms, Family);
1810 AllocationFamily Family)
const {
1814 const Expr *CE =
Call.getOriginExpr();
1823 unsigned Count =
C.blockCount();
1830 State = State->BindExpr(CE,
C.getLocationContext(), RetVal);
1833 State = State->bindDefaultInitial(RetVal,
Init, LCtx);
1839 checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
1850 AllocationFamily Family,
1851 std::optional<SVal> RetVal) {
1857 RetVal =
C.getSVal(
E);
1860 if (!RetVal->getAs<
Loc>())
1863 SymbolRef Sym = RetVal->getAsLocSymbol();
1878 return State->set<RegionState>(Sym, RefState::getAllocated(Family,
E));
1883 const OwnershipAttr *Att,
1888 auto attrClassName = Att->getModule()->getName();
1889 auto Family = AllocationFamily(AF_Custom, attrClassName);
1891 bool IsKnownToBeAllocated =
false;
1893 for (
const auto &Arg : Att->args()) {
1895 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
1896 Att->getOwnKind() == OwnershipAttr::Holds,
1897 IsKnownToBeAllocated, Family);
1907 bool Hold,
bool &IsKnownToBeAllocated,
1908 AllocationFamily Family,
1909 bool ReturnsNullOnFailure)
const {
1913 if (
Call.getNumArgs() < (Num + 1))
1916 return FreeMemAux(
C,
Call.getArgExpr(Num),
Call, State, Hold,
1917 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
1924 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
1926 assert(*Ret &&
"We should not store the null return symbol");
1929 RetStatusSymbol = *Ret;
1937 const CallExpr *CE = dyn_cast<CallExpr>(
E);
1948 if (I->getOwnKind() != OwnershipAttr::Takes)
1951 os <<
", which takes ownership of '" << I->getModule()->
getName() <<
'\'';
1957 if (
const CallExpr *CE = dyn_cast<CallExpr>(
E)) {
1973 if (Msg->isInstanceMessage())
1977 Msg->getSelector().
print(os);
1981 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(
E)) {
2000 switch (Family.Kind) {
2007 case AF_CXXNewArray:
2010 case AF_IfNameIndex:
2011 os <<
"'if_nameindex()'";
2013 case AF_InnerBuffer:
2014 os <<
"container-specific allocator";
2017 os << Family.CustomName.value();
2021 assert(
false &&
"not a deallocation expression");
2026 switch (Family.Kind) {
2033 case AF_CXXNewArray:
2036 case AF_IfNameIndex:
2037 os <<
"'if_freenameindex()'";
2039 case AF_InnerBuffer:
2040 os <<
"container-specific deallocator";
2043 os <<
"function that takes ownership of '" << Family.CustomName.value()
2048 assert(
false &&
"not a deallocation expression");
2055 bool Hold,
bool &IsKnownToBeAllocated,
2056 AllocationFamily Family,
bool ReturnsNullOnFailure,
2057 std::optional<SVal> ArgValOpt)
const {
2062 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2063 if (!isa<DefinedOrUnknownSVal>(ArgVal))
2068 if (!isa<Loc>(location))
2073 std::tie(notNullState, nullState) = State->assume(location);
2074 if (nullState && !notNullState)
2083 const Expr *ParentExpr =
Call.getOriginExpr();
2102 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2103 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2111 if (isa<BlockDataRegion>(R)) {
2112 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2121 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
2127 if (isa<AllocaRegion>(R))
2130 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2143 const RefState *RsBase = State->get<RegionState>(SymBase);
2144 SymbolRef PreviousRetStatusSymbol =
nullptr;
2146 IsKnownToBeAllocated =
2147 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2152 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2158 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2160 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2161 SymBase, PreviousRetStatusSymbol);
2166 }
else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2167 RsBase->isEscaped()) {
2170 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2171 if (!DeallocMatchesAlloc) {
2173 RsBase, SymBase, Hold);
2180 if (Offset.isValid() &&
2181 !Offset.hasSymbolicOffset() &&
2182 Offset.getOffset() != 0) {
2183 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2192 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2198 State = State->remove<FreeReturnValue>(SymBase);
2202 if (ReturnsNullOnFailure) {
2203 SVal RetVal =
C.getSVal(ParentExpr);
2205 if (RetStatusSymbol) {
2206 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2207 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2215 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2219 return State->set<RegionState>(SymBase,
2220 RefState::getRelinquished(Family,
2223 return State->set<RegionState>(SymBase,
2224 RefState::getReleased(Family, ParentExpr));
2227std::optional<MallocChecker::CheckKind>
2228MallocChecker::getCheckIfTracked(AllocationFamily Family,
2229 bool IsALeakCheck)
const {
2230 switch (Family.Kind) {
2234 case AF_IfNameIndex: {
2235 if (ChecksEnabled[CK_MallocChecker])
2236 return CK_MallocChecker;
2237 return std::nullopt;
2240 case AF_CXXNewArray: {
2242 if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2243 return CK_NewDeleteLeaksChecker;
2246 if (ChecksEnabled[CK_NewDeleteChecker])
2247 return CK_NewDeleteChecker;
2249 return std::nullopt;
2251 case AF_InnerBuffer: {
2252 if (ChecksEnabled[CK_InnerPointerChecker])
2253 return CK_InnerPointerChecker;
2254 return std::nullopt;
2257 assert(
false &&
"no family");
2258 return std::nullopt;
2261 assert(
false &&
"unhandled family");
2262 return std::nullopt;
2265std::optional<MallocChecker::CheckKind>
2267 bool IsALeakCheck)
const {
2268 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2269 return CK_MallocChecker;
2271 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2273 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2276bool MallocChecker::SummarizeValue(raw_ostream &os,
SVal V) {
2277 if (std::optional<nonloc::ConcreteInt> IntVal =
2279 os <<
"an integer (" << IntVal->getValue() <<
")";
2280 else if (std::optional<loc::ConcreteInt> ConstAddr =
2282 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2284 os <<
"the address of the label '" <<
Label->getLabel()->getName() <<
"'";
2291bool MallocChecker::SummarizeRegion(raw_ostream &os,
2294 case MemRegion::FunctionCodeRegionKind: {
2295 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2297 os <<
"the address of the function '" << *FD <<
'\'';
2299 os <<
"the address of a function";
2302 case MemRegion::BlockCodeRegionKind:
2305 case MemRegion::BlockDataRegionKind:
2312 if (isa<StackLocalsSpaceRegion>(MS)) {
2313 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2321 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2323 os <<
"the address of a local stack variable";
2327 if (isa<StackArgumentsSpaceRegion>(MS)) {
2328 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2336 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2338 os <<
"the address of a parameter";
2342 if (isa<GlobalsSpaceRegion>(MS)) {
2343 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2352 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2354 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2356 os <<
"the address of a global variable";
2367 const Expr *DeallocExpr,
2368 AllocationFamily Family)
const {
2370 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2375 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2380 if (!BT_BadFree[*CheckKind])
2381 BT_BadFree[*CheckKind].reset(
new BugType(
2385 llvm::raw_svector_ostream os(buf);
2388 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2389 MR = ER->getSuperRegion();
2391 os <<
"Argument to ";
2393 os <<
"deallocator";
2396 bool Summarized = MR ? SummarizeRegion(os, MR)
2397 : SummarizeValue(os, ArgVal);
2399 os <<
", which is not memory allocated by ";
2401 os <<
"not memory allocated by ";
2405 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2407 R->markInteresting(MR);
2409 C.emitReport(std::move(R));
2416 std::optional<MallocChecker::CheckKind> CheckKind;
2418 if (ChecksEnabled[CK_MallocChecker])
2419 CheckKind = CK_MallocChecker;
2420 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2421 CheckKind = CK_MismatchedDeallocatorChecker;
2428 if (!BT_FreeAlloca[*CheckKind])
2429 BT_FreeAlloca[*CheckKind].reset(
new BugType(
2432 auto R = std::make_unique<PathSensitiveBugReport>(
2433 *BT_FreeAlloca[*CheckKind],
2434 "Memory allocated by 'alloca()' should not be deallocated", N);
2437 C.emitReport(std::move(R));
2443 const Expr *DeallocExpr,
2445 bool OwnershipTransferred)
const {
2447 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2453 if (!BT_MismatchedDealloc)
2454 BT_MismatchedDealloc.reset(
2455 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2459 llvm::raw_svector_ostream os(buf);
2461 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2463 llvm::raw_svector_ostream AllocOs(AllocBuf);
2465 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2467 if (OwnershipTransferred) {
2469 os << DeallocOs.str() <<
" cannot";
2473 os <<
" take ownership of memory";
2476 os <<
" allocated by " << AllocOs.str();
2480 os <<
" allocated by " << AllocOs.str();
2482 os <<
" should be deallocated by ";
2486 os <<
", not " << DeallocOs.str();
2491 auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2493 R->markInteresting(Sym);
2495 R->addVisitor<MallocBugVisitor>(Sym);
2496 C.emitReport(std::move(R));
2502 AllocationFamily Family,
2503 const Expr *AllocExpr)
const {
2505 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2510 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2518 if (!BT_OffsetFree[*CheckKind])
2519 BT_OffsetFree[*CheckKind].reset(
new BugType(
2523 llvm::raw_svector_ostream os(buf);
2525 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2528 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2531 assert((Offset.isValid() &&
2532 !Offset.hasSymbolicOffset() &&
2533 Offset.getOffset() != 0) &&
2534 "Only symbols with a valid offset can have offset free errors");
2536 int offsetBytes = Offset.getOffset() /
C.getASTContext().getCharWidth();
2538 os <<
"Argument to ";
2540 os <<
"deallocator";
2541 os <<
" is offset by "
2544 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2545 <<
" from the start of ";
2547 os <<
"memory allocated by " << AllocNameOs.str();
2549 os <<
"allocated memory";
2551 auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2555 C.emitReport(std::move(R));
2561 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2562 !ChecksEnabled[CK_InnerPointerChecker]) {
2567 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2572 if (!BT_UseFree[*CheckKind])
2573 BT_UseFree[*CheckKind].reset(
new BugType(
2576 AllocationFamily AF =
2577 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2579 auto R = std::make_unique<PathSensitiveBugReport>(
2580 *BT_UseFree[*CheckKind],
2581 AF.Kind == AF_InnerBuffer
2582 ?
"Inner pointer of container used after re/deallocation"
2583 :
"Use of memory after it is freed",
2586 R->markInteresting(Sym);
2588 R->addVisitor<MallocBugVisitor>(Sym);
2590 if (AF.Kind == AF_InnerBuffer)
2593 C.emitReport(std::move(R));
2601 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2606 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2611 if (!BT_DoubleFree[*CheckKind])
2612 BT_DoubleFree[*CheckKind].reset(
new BugType(
2615 auto R = std::make_unique<PathSensitiveBugReport>(
2616 *BT_DoubleFree[*CheckKind],
2617 (Released ?
"Attempt to free released memory"
2618 :
"Attempt to free non-owned memory"),
2621 R->markInteresting(Sym);
2623 R->markInteresting(PrevSym);
2624 R->addVisitor<MallocBugVisitor>(Sym);
2625 C.emitReport(std::move(R));
2631 if (!ChecksEnabled[CK_NewDeleteChecker]) {
2636 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2641 if (!BT_DoubleDelete)
2642 BT_DoubleDelete.reset(
new BugType(CheckNames[CK_NewDeleteChecker],
2646 auto R = std::make_unique<PathSensitiveBugReport>(
2647 *BT_DoubleDelete,
"Attempt to delete released memory", N);
2649 R->markInteresting(Sym);
2650 R->addVisitor<MallocBugVisitor>(Sym);
2651 C.emitReport(std::move(R));
2658 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2663 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2669 if (!BT_UseZerroAllocated[*CheckKind])
2670 BT_UseZerroAllocated[*CheckKind].reset(
2671 new BugType(CheckNames[*CheckKind],
"Use of zero allocated",
2674 auto R = std::make_unique<PathSensitiveBugReport>(
2675 *BT_UseZerroAllocated[*CheckKind],
2676 "Use of memory allocated with size zero", N);
2680 R->markInteresting(Sym);
2681 R->addVisitor<MallocBugVisitor>(Sym);
2683 C.emitReport(std::move(R));
2689 const Expr *FreeExpr,
2690 AllocationFamily Family)
const {
2691 if (!ChecksEnabled[CK_MallocChecker]) {
2696 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2701 if (!BT_BadFree[*CheckKind])
2702 BT_BadFree[*CheckKind].reset(
new BugType(
2706 llvm::raw_svector_ostream Os(Buf);
2709 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2710 MR = ER->getSuperRegion();
2712 Os <<
"Argument to ";
2714 Os <<
"deallocator";
2716 Os <<
" is a function pointer";
2718 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2720 R->markInteresting(MR);
2722 C.emitReport(std::move(R));
2729 AllocationFamily Family,
bool SuffixWithN)
const {
2733 const CallExpr *CE = cast<CallExpr>(
Call.getOriginExpr());
2741 SVal Arg0Val =
C.getSVal(arg0Expr);
2742 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2749 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2755 SVal TotalSize =
C.getSVal(Arg1);
2757 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2758 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2764 svalBuilder.makeIntValWithWidth(
2765 svalBuilder.getContext().getSizeType(), 0));
2768 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2770 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2773 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2774 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2778 if (PrtIsNull && !SizeIsZero) {
2784 if (PrtIsNull && SizeIsZero)
2789 bool IsKnownToBeAllocated =
false;
2798 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2803 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2810 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2811 if (ShouldFreeOnFail)
2812 Kind = OAR_FreeOnFailure;
2813 else if (!IsKnownToBeAllocated)
2814 Kind = OAR_DoNotTrackAfterFailure;
2818 SVal RetVal =
C.getSVal(CE);
2820 assert(FromPtr && ToPtr &&
2821 "By this point, FreeMemAux and MallocMemAux should have checked "
2822 "whether the argument or the return value is symbolic!");
2826 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2827 ReallocPair(FromPtr, Kind));
2829 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2830 return stateRealloc;
2841 if (
Call.getNumArgs() < 2)
2847 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2849 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State,
2850 AllocationFamily(AF_Malloc));
2853MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2860 const MemRegion *ReferenceRegion =
nullptr;
2864 if (!State->get<RegionState>(Sym))
2869 if (!ReferenceRegion) {
2870 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
2871 SVal Val = State->getSVal(MR);
2877 ReferenceRegion = MR;
2885 if (NContext == LeakContext ||
2891 return LeakInfo(AllocNode, ReferenceRegion);
2897 if (!ChecksEnabled[CK_MallocChecker] &&
2898 !ChecksEnabled[CK_NewDeleteLeaksChecker])
2901 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2902 assert(RS &&
"cannot leak an untracked symbol");
2903 AllocationFamily Family = RS->getAllocationFamily();
2905 if (Family.Kind == AF_Alloca)
2908 std::optional<MallocChecker::CheckKind> CheckKind =
2909 getCheckIfTracked(Family,
true);
2915 if (!BT_Leak[*CheckKind]) {
2921 BT_Leak[*CheckKind].reset(
new BugType(CheckNames[*CheckKind],
"Memory leak",
2932 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
2937 C.getSourceManager(),
2941 llvm::raw_svector_ostream os(buf);
2943 os <<
"Potential leak of memory pointed to by ";
2946 os <<
"Potential memory leak";
2949 auto R = std::make_unique<PathSensitiveBugReport>(
2950 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
2952 R->markInteresting(Sym);
2953 R->addVisitor<MallocBugVisitor>(Sym,
true);
2954 if (ShouldRegisterNoOwnershipChangeVisitor)
2955 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
2956 C.emitReport(std::move(R));
2959void MallocChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
2963 RegionStateTy OldRS = state->get<RegionState>();
2964 RegionStateTy::Factory &F = state->get_context<RegionState>();
2966 RegionStateTy RS = OldRS;
2968 for (
auto [Sym, State] : RS) {
2969 if (SymReaper.
isDead(Sym)) {
2970 if (State.isAllocated() || State.isAllocatedOfSizeZero())
2971 Errors.push_back(Sym);
2973 RS = F.remove(RS, Sym);
2979 assert(state->get<ReallocPairs>() ==
2980 C.getState()->get<ReallocPairs>());
2981 assert(state->get<FreeReturnValue>() ==
2982 C.getState()->get<FreeReturnValue>());
2987 ReallocPairsTy RP = state->get<ReallocPairs>();
2988 for (
auto [Sym, ReallocPair] : RP) {
2989 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
2990 state = state->remove<ReallocPairs>(Sym);
2995 FreeReturnValueTy FR = state->get<FreeReturnValue>();
2996 for (
auto [Sym, RetSym] : FR) {
2997 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
2998 state = state->remove<FreeReturnValue>(Sym);
3004 if (!Errors.empty()) {
3006 N =
C.generateNonFatalErrorNode(
C.getState(), &Tag);
3009 HandleLeak(Sym, N,
C);
3014 C.addTransition(state->set<RegionState>(RS), N);
3020 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3023 if (!ChecksEnabled[CK_NewDeleteChecker])
3031 bool IsKnownToBeAllocated;
3034 false, IsKnownToBeAllocated,
3035 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3037 C.addTransition(State);
3041 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3042 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3043 if (!Sym || checkDoubleDelete(Sym,
C))
3049 if (
const auto *PreFN = PreFnMap.lookup(
Call)) {
3050 (*PreFN)(
this,
Call,
C);
3060 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(
Call))
3066 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3067 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3072 for (
unsigned I = 0,
E =
Call.getNumArgs(); I !=
E; ++I) {
3074 if (isa<Loc>(ArgSVal)) {
3078 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3084void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3086 checkEscapeOnReturn(S,
C);
3092void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3094 checkEscapeOnReturn(S,
C);
3097void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3102 const Expr *
E = S->getRetValue();
3108 SVal RetVal =
C.getSVal(
E);
3115 if (isa<FieldRegion, ElementRegion>(MR))
3118 Sym = BMR->getSymbol();
3122 checkUseAfterFree(Sym,
C,
E);
3128void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3138 cast<BlockDataRegion>(
C.getSVal(BE).getAsRegion());
3141 if (ReferencedVars.empty())
3148 for (
const auto &Var : ReferencedVars) {
3149 const VarRegion *VR = Var.getCapturedRegion();
3153 Regions.push_back(VR);
3157 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3158 C.addTransition(state);
3163 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3164 return (RS && RS->isReleased());
3167bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3169 if (
Call.getNumArgs() == 0)
3172 StringRef FunctionStr =
"";
3173 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3175 if (Body->getBeginLoc().isValid())
3179 C.getSourceManager(),
C.getLangOpts());
3182 if (!FunctionStr.contains(
"__isl_"))
3187 for (
const Expr *Arg : cast<CallExpr>(
Call.getOriginExpr())->arguments())
3188 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3189 if (
const RefState *RS = State->get<RegionState>(Sym))
3190 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3192 C.addTransition(State);
3197 const Stmt *S)
const {
3200 HandleUseAfterFree(
C, S->getSourceRange(), Sym);
3208 const Stmt *S)
const {
3211 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3212 if (RS->isAllocatedOfSizeZero())
3213 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3215 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3216 HandleUseZeroAlloc(
C, S->getSourceRange(), Sym);
3223 HandleDoubleDelete(
C, Sym);
3230void MallocChecker::checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
3234 checkUseAfterFree(Sym,
C, S);
3235 checkUseZeroAllocated(Sym,
C, S);
3243 bool Assumption)
const {
3244 RegionStateTy RS = state->get<RegionState>();
3245 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3250 state = state->remove<RegionState>(Sym);
3255 ReallocPairsTy RP = state->get<ReallocPairs>();
3256 for (
auto [Sym, ReallocPair] : RP) {
3263 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3264 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3265 if (RS->isReleased()) {
3266 switch (ReallocPair.Kind) {
3267 case OAR_ToBeFreedAfterFailure:
3268 state = state->set<RegionState>(ReallocSym,
3269 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3271 case OAR_DoNotTrackAfterFailure:
3272 state = state->remove<RegionState>(ReallocSym);
3275 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3279 state = state->remove<ReallocPairs>(Sym);
3285bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3290 EscapingSymbol =
nullptr;
3296 if (!isa<SimpleFunctionCall, ObjCMethodCall>(
Call))
3303 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3316 return *FreeWhenDone;
3322 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3323 if (FirstSlot.ends_with(
"NoCopy"))
3330 if (FirstSlot.starts_with(
"addPointer") ||
3331 FirstSlot.starts_with(
"insertPointer") ||
3332 FirstSlot.starts_with(
"replacePointer") ||
3333 FirstSlot ==
"valueWithPointer") {
3340 if (Msg->getMethodFamily() ==
OMF_init) {
3341 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3357 if (isMemCall(*
Call))
3361 if (!
Call->isInSystemHeader())
3368 StringRef FName = II->
getName();
3372 if (FName.ends_with(
"NoCopy")) {
3376 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3377 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3378 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3379 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3380 if (DeallocatorName ==
"kCFAllocatorNull")
3391 if (FName ==
"funopen")
3392 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3398 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3399 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3400 if (
Call->getNumArgs() >= 1) {
3401 const Expr *ArgE =
Call->getArgExpr(0)->IgnoreParenCasts();
3402 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3403 if (
const VarDecl *
D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3414 if (FName ==
"CGBitmapContextCreate" ||
3415 FName ==
"CGBitmapContextCreateWithData" ||
3416 FName ==
"CVPixelBufferCreateWithBytes" ||
3417 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3418 FName ==
"OSAtomicEnqueue") {
3422 if (FName ==
"postEvent" &&
3427 if (FName ==
"connectImpl" &&
3432 if (FName ==
"singleShotImpl" &&
3441 if (
Call->argumentsMayEscape())
3453 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3462 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3467 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3468 RS->getAllocationFamily().Kind == AF_CXXNew);
3474 bool IsConstPointerEscape)
const {
3479 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3486 if (EscapingSymbol && EscapingSymbol != sym)
3489 if (
const RefState *RS = State->get<RegionState>(sym))
3490 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3492 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3498 SVal ArgVal)
const {
3499 if (!KernelZeroSizePtrValue)
3500 KernelZeroSizePtrValue =
3503 const llvm::APSInt *ArgValKnown =
3504 C.getSValBuilder().getKnownValue(State, ArgVal);
3505 return ArgValKnown && *KernelZeroSizePtrValue &&
3506 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3511 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3512 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3514 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3516 if (!currMap.lookup(sym))
3526 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3527 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3528 N.contains_insensitive(
"intrusive") ||
3529 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3543 const RefState *RSCurr = state->get<RegionState>(Sym);
3544 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3549 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3561 if (ReleaseDestructorLC && (ReleaseDestructorLC == CurrentLC ||
3562 ReleaseDestructorLC->
isParentOf(CurrentLC))) {
3563 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3566 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3567 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3570 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
3573 if (
const auto *MD =
3590 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3592 llvm::raw_svector_ostream OS(Buf);
3595 if (isAllocated(RSCurr, RSPrev, S)) {
3596 Msg =
"Memory is allocated";
3597 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3598 Sym,
"Returned allocated memory");
3600 const auto Family = RSCurr->getAllocationFamily();
3601 switch (Family.Kind) {
3606 case AF_CXXNewArray:
3607 case AF_IfNameIndex:
3608 Msg =
"Memory is released";
3609 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3610 Sym,
"Returning; memory was released");
3612 case AF_InnerBuffer: {
3615 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
3617 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
3620 OS <<
"deallocated by call to destructor";
3621 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3622 Sym,
"Returning; inner buffer was deallocated");
3624 OS <<
"reallocated by call to '";
3625 const Stmt *S = RSCurr->getStmt();
3626 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3627 OS << MemCallE->getMethodDecl()->getDeclName();
3628 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3629 OS << OpCallE->getDirectCallee()->getDeclName();
3630 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
3633 CEMgr.getSimpleCall(CallE, state, CurrentLC, {
nullptr, 0});
3634 if (
const auto *
D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
3635 OS <<
D->getDeclName();
3640 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3641 Sym,
"Returning; inner buffer was reallocated");
3647 assert(
false &&
"Unhandled allocation family!");
3654 bool FoundAnyDestructor =
false;
3656 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
3662 }
else if (!FoundAnyDestructor) {
3663 assert(!ReleaseDestructorLC &&
3664 "There can be only one release point!");
3676 FoundAnyDestructor =
true;
3680 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
3681 Msg =
"Memory ownership is transferred";
3682 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
3683 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3684 Mode = ReallocationFailed;
3685 Msg =
"Reallocation failed";
3686 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3687 Sym,
"Reallocation failed");
3691 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3692 "We only support one failed realloc at a time.");
3694 FailedReallocSymbol = sym;
3699 }
else if (Mode == ReallocationFailed) {
3700 assert(FailedReallocSymbol &&
"No symbol to look for.");
3703 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3705 Msg =
"Attempt to reallocate memory";
3706 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3707 Sym,
"Returned reallocated memory");
3708 FailedReallocSymbol =
nullptr;
3723 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
3734 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
3739void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
3740 const char *NL,
const char *Sep)
const {
3742 RegionStateTy RS = State->get<RegionState>();
3744 if (!RS.isEmpty()) {
3745 Out << Sep <<
"MallocChecker :" << NL;
3746 for (
auto [Sym,
Data] : RS) {
3747 const RefState *RefS = State->get<RegionState>(Sym);
3748 AllocationFamily Family = RefS->getAllocationFamily();
3749 std::optional<MallocChecker::CheckKind> CheckKind =
3750 getCheckIfTracked(Family);
3752 CheckKind = getCheckIfTracked(Family,
true);
3758 Out <<
" (" << CheckNames[*CheckKind].getName() <<
")";
3766namespace allocation_state {
3770 AllocationFamily Family(AF_InnerBuffer);
3771 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3781 MallocChecker *checker = mgr.
getChecker<MallocChecker>();
3782 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] =
true;
3783 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3789 checker->ShouldIncludeOwnershipAnnotatedFunctions =
3791 checker->ShouldRegisterNoOwnershipChangeVisitor =
3793 checker,
"AddNoOwnershipChangeNotes");
3796bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
3800#define REGISTER_CHECKER(name) \
3801 void ento::register##name(CheckerManager &mgr) { \
3802 MallocChecker *checker = mgr.getChecker<MallocChecker>(); \
3803 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
3804 checker->CheckNames[MallocChecker::CK_##name] = \
3805 mgr.getCurrentCheckerName(); \
3808 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
enum clang::sema::@1653::IndirectLocalPathEntry::EntryKind Kind
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 void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool isStandardNewDelete(const FunctionDecl *FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
static bool contains(const std::set< tok::TokenKind > &Terminators, const Token &Tok)
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
__device__ __2f16 float __ockl_bool s
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Represents a C++ constructor within a class.
Represents a delete expression for memory deallocation and destructor calls, e.g.
Represents a C++ destructor within a class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Represents a C++ struct/union/class.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
static CharSourceRange getTokenRange(SourceRange R)
DeclContext * getParent()
getParent - Returns the containing DeclContext.
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
ASTContext & getASTContext() const LLVM_READONLY
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
SourceLocation getLocation() const
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
ArrayRef< ParmVarDecl * > parameters() const
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
QualType getDeclaredReturnType() const
Get the declared return type, which may differ from the actual return type if the return type is dedu...
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
This represents a decl that may have a name.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
An expression that sends a message to the given Objective-C object or class.
bool isConsumedExpr(Expr *E) const
Represents a program point just after an implicit call event.
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Smart pointer class that efficiently represents Objective-C method names.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
A trivial tuple used to represent a source range.
It represents a stack frame of the call stack (based on CallEvent).
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isFunctionPointerType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Maps string IDs to AST nodes matched by parts of a matcher.
A record of the "type" of an APSInt, used for conversions.
Represents a call to any sort of function that might have a FunctionDecl.
const llvm::APSInt & getMaxValue(const llvm::APSInt &v)
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 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
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...
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.
BasicValueFactory & getBasicValueFactory()
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
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.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
const MemRegion * getAsRegion() const
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
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.
const char *const MemoryError
const char *const TaintedData
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given Statement and state.
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.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
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.
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 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)
bool operator!=(CanQual< T > x, CanQual< U > y)
const FunctionProtoType * T
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.
@ Other
Other implicit parameter.