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 &&
320 if (!
Call.getDecl() || !isa<FunctionDecl>(
Call.getDecl()))
327 if (!
Call.getDecl() || !isa<FunctionDecl>(
Call.getDecl()))
345 :
public Checker<check::DeadSymbols, check::PointerEscape,
346 check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
347 check::EndFunction, check::PreCall, check::PostCall,
348 eval::Call, check::NewAllocator,
349 check::PostStmt<BlockExpr>, check::PostObjCMessage,
350 check::Location, eval::Assume> {
356 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
358 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
368 CK_NewDeleteLeaksChecker,
369 CK_MismatchedDeallocatorChecker,
370 CK_InnerPointerChecker,
371 CK_TaintedAllocChecker,
375 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
377 bool ChecksEnabled[CK_NumCheckKinds] = {
false};
390 bool Assumption)
const;
391 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
404 const char *NL,
const char *Sep)
const override;
407 mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];
408 mutable std::unique_ptr<BugType> BT_DoubleDelete;
409 mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];
410 mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];
411 mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
412 mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
413 mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
414 mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
415 mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
416 mutable std::unique_ptr<BugType> BT_TaintedAlloc;
418#define CHECK_FN(NAME) \
419 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
450 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetdelim},
451 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetdelim},
457 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetdelim},
458 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::checkGetdelim},
462 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
463 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
464 &MallocChecker::checkIfFreeNameIndex},
465 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
466 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
471 static bool isFreeingOwnershipAttrCall(
const CallEvent &
Call);
473 static bool isAllocatingOwnershipAttrCall(
const CallEvent &
Call);
475 friend class NoMemOwnershipChangeVisitor;
478 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
479 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
483 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
484 &MallocChecker::checkAlloca},
488 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
489 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
490 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
491 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
492 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
493 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
494 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
495 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
496 {{CDM::CLibrary, {
"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
497 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
498 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
499 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
500 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
501 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
502 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
503 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
504 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
505 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
506 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
507 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
511 {{CDM::CLibrary, {
"realloc"}, 2},
512 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
513 {{CDM::CLibrary, {
"reallocf"}, 2},
514 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
true)},
515 {{CDM::CLibrary, {
"g_realloc"}, 2},
516 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
517 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
518 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
519 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
520 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
528 AllocationFamily Family)
const;
532 AllocationFamily Family)
const;
535 mutable std::optional<uint64_t> KernelZeroFlagVal;
537 using KernelZeroSizePtrValueTy = std::optional<int>;
542 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
548 AllocationFamily Family)
const;
561 std::optional<SVal> RetVal = std::nullopt);
592 bool isAlloca)
const;
619 AllocationFamily Family)
const;
623 [[nodiscard]] std::optional<ProgramStateRef>
646 const OwnershipAttr *Att,
670 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
671 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
697 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
698 std::optional<SVal> ArgValOpt = {})
const;
716 bool SuffixWithN =
false)
const;
725 const Expr *BlockBytes);
738 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
747 const Stmt *S)
const;
762 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
771 bool IsConstPointerEscape)
const;
780 std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
781 bool IsALeakCheck =
false)
const;
784 bool IsALeakCheck =
false)
const;
786 static bool SummarizeValue(raw_ostream &os,
SVal V);
787 static bool SummarizeRegion(raw_ostream &os,
const MemRegion *MR);
790 const Expr *DeallocExpr,
791 AllocationFamily Family)
const;
797 const Expr *DeallocExpr,
const RefState *RS,
798 SymbolRef Sym,
bool OwnershipTransferred)
const;
801 const Expr *DeallocExpr, AllocationFamily Family,
802 const Expr *AllocExpr =
nullptr)
const;
816 const Expr *FreeExpr,
817 AllocationFamily Family)
const;
846 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
847 const auto *MallocChk =
static_cast<const MallocChecker *
>(&
Checker);
848 if (MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
849 MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
852 if (
const auto *
Func =
853 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
854 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
861 return CallEnterState->get<RegionState>(Sym) !=
862 CallExitEndState->get<RegionState>(Sym);
869 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
871 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
890 if (
const auto *
Call = Match.getNodeAs<
CallExpr>(
"call"))
891 if (isFreeingCallAsWritten(*
Call))
903 N->getState()->getStateManager().getContext().getSourceManager());
904 return std::make_shared<PathDiagnosticEventPiece>(
905 L,
"Returning without deallocating memory or storing the pointer for "
906 "later deallocation");
913 void Profile(llvm::FoldingSetNodeID &ID)
const override {
932 enum NotificationMode {
Normal, ReallocationFailed };
938 NotificationMode Mode;
950 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
951 : Sym(S), Mode(
Normal), FailedReallocSymbol(nullptr),
952 ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}
954 static void *getTag() {
959 void Profile(llvm::FoldingSetNodeID &ID)
const override {
960 ID.AddPointer(getTag());
965 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
967 return (isa_and_nonnull<CallExpr, CXXNewExpr>(
Stmt) &&
969 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
971 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
976 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
979 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
980 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(
Stmt)) ||
981 (!
Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
986 static inline bool isRelinquished(
const RefState *RSCurr,
987 const RefState *RSPrev,
const Stmt *
Stmt) {
989 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(
Stmt) &&
990 (RSCurr && RSCurr->isRelinquished()) &&
991 (!RSPrev || !RSPrev->isRelinquished()));
998 static inline bool hasReallocFailed(
const RefState *RSCurr,
999 const RefState *RSPrev,
1001 return ((!isa_and_nonnull<CallExpr>(
Stmt)) &&
1003 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1005 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1020 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1025 class StackHintGeneratorForReallocationFailed
1028 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1031 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1036 llvm::raw_svector_ostream os(buf);
1038 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1039 <<
" parameter failed";
1041 return std::string(os.str());
1045 return "Reallocation of returned value failed";
1064 state = state->remove<RegionState>(sym);
1075 if (Kind != OO_New && Kind != OO_Array_New)
1091 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1102 return L.
isInvalid() || (!HasBody &&
SM.isInSystemHeader(L));
1109bool MallocChecker::isFreeingOwnershipAttrCall(
const CallEvent &
Call) {
1110 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1112 return Func && isFreeingOwnershipAttrCall(
Func);
1116 if (
Func->hasAttrs()) {
1117 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1118 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1119 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1126bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1127 if (FreeingMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1130 return isFreeingOwnershipAttrCall(
Call);
1133bool MallocChecker::isAllocatingOwnershipAttrCall(
const CallEvent &
Call) {
1134 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1136 return Func && isAllocatingOwnershipAttrCall(
Func);
1139bool MallocChecker::isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func) {
1140 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1141 if (I->getOwnKind() == OwnershipAttr::Returns)
1149 if (FreeingMemFnMap.lookup(
Call) || AllocatingMemFnMap.lookup(
Call) ||
1150 AllocaMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1153 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1156 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1157 return Func &&
Func->hasAttr<OwnershipAttr>();
1160std::optional<ProgramStateRef>
1182 if (!KernelZeroFlagVal) {
1184 case llvm::Triple::FreeBSD:
1185 KernelZeroFlagVal = 0x0100;
1187 case llvm::Triple::NetBSD:
1188 KernelZeroFlagVal = 0x0002;
1190 case llvm::Triple::OpenBSD:
1191 KernelZeroFlagVal = 0x0008;
1193 case llvm::Triple::Linux:
1195 KernelZeroFlagVal = 0x8000;
1203 return std::nullopt;
1210 if (
Call.getNumArgs() < 2)
1211 return std::nullopt;
1213 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1214 const SVal V =
C.getSVal(FlagsEx);
1215 if (!isa<NonLoc>(
V)) {
1218 return std::nullopt;
1222 NonLoc ZeroFlag =
C.getSValBuilder()
1223 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1225 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1229 return std::nullopt;
1234 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1237 if (TrueState && !FalseState) {
1238 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1239 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1240 AllocationFamily(AF_Malloc));
1243 return std::nullopt;
1247 const Expr *BlockBytes) {
1249 SVal BlocksVal =
C.getSVal(Blocks);
1250 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1252 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1261 AllocationFamily(AF_Malloc));
1262 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1263 C.addTransition(State);
1269 std::optional<ProgramStateRef> MaybeState =
1270 performKernelMalloc(
Call,
C, State);
1272 State = *MaybeState;
1275 AllocationFamily(AF_Malloc));
1276 C.addTransition(State);
1303 bool ShouldFreeOnFail)
const {
1312 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1313 AllocationFamily(AF_Malloc));
1314 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1315 C.addTransition(State);
1320 State = CallocMem(
C,
Call, State);
1321 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1322 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1323 C.addTransition(State);
1328 bool IsKnownToBeAllocatedMemory =
false;
1329 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1331 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1332 AllocationFamily(AF_Malloc));
1333 C.addTransition(State);
1339 AllocationFamily(AF_Alloca));
1340 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1341 C.addTransition(State);
1346 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1350 AllocationFamily(AF_Malloc));
1352 C.addTransition(State);
1361 AllocationFamily(AF_IfNameIndex));
1363 C.addTransition(State);
1369 bool IsKnownToBeAllocatedMemory =
false;
1370 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1371 AllocationFamily(AF_IfNameIndex));
1372 C.addTransition(State);
1378 bool IsKnownToBeAllocatedMemory =
false;
1379 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1393 AllocationFamily(AF_CXXNew));
1394 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1398 AllocationFamily(AF_CXXNewArray));
1399 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1402 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1403 AllocationFamily(AF_CXXNew));
1405 case OO_Array_Delete:
1406 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1407 AllocationFamily(AF_CXXNewArray));
1410 assert(
false &&
"not a new/delete operator");
1414 C.addTransition(State);
1421 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1422 AllocationFamily(AF_Malloc));
1423 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1424 C.addTransition(State);
1430 AllocationFamily(AF_Malloc));
1431 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1432 C.addTransition(State);
1438 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1439 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1440 AllocationFamily(AF_Malloc));
1441 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1442 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1443 C.addTransition(State);
1450 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1451 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1452 AllocationFamily(AF_Malloc));
1453 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1454 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1455 C.addTransition(State);
1460 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1479 bool IsKnownToBeAllocated =
false;
1480 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1481 IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1484 C.addTransition(State);
1496 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1500 const auto LinePtr =
1504 if (!LinePtr || !Size || !LinePtr->getAsRegion())
1509 AllocationFamily(AF_Malloc), *LinePtr));
1514 State = ReallocMemAux(
C,
Call,
false, State,
1515 AllocationFamily(AF_Malloc),
1517 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1518 State = ProcessZeroAllocCheck(
C,
Call, 2, State);
1519 C.addTransition(State);
1525 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1531 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1532 ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1537 switch (I->getOwnKind()) {
1538 case OwnershipAttr::Returns:
1539 State = MallocMemReturnsAttr(
C,
Call, I, State);
1541 case OwnershipAttr::Takes:
1542 case OwnershipAttr::Holds:
1543 State = FreeMemAttr(
C,
Call, I, State);
1548 C.addTransition(State);
1552 if (!
Call.getOriginExpr())
1557 if (
const CheckFn *Callback = FreeingMemFnMap.lookup(
Call)) {
1558 (*Callback)(
this, State,
Call,
C);
1562 if (
const CheckFn *Callback = AllocatingMemFnMap.lookup(
Call)) {
1563 State = MallocBindRetVal(
C,
Call, State,
false);
1564 (*Callback)(
this, State,
Call,
C);
1568 if (
const CheckFn *Callback = ReallocatingMemFnMap.lookup(
Call)) {
1569 State = MallocBindRetVal(
C,
Call, State,
false);
1570 (*Callback)(
this, State,
Call,
C);
1575 State = MallocBindRetVal(
C,
Call, State,
false);
1576 checkCXXNewOrCXXDelete(State,
Call,
C);
1581 checkCXXNewOrCXXDelete(State,
Call,
C);
1585 if (
const CheckFn *Callback = AllocaMemFnMap.lookup(
Call)) {
1586 State = MallocBindRetVal(
C,
Call, State,
true);
1587 (*Callback)(
this, State,
Call,
C);
1591 if (isFreeingOwnershipAttrCall(
Call)) {
1592 checkOwnershipAttr(State,
Call,
C);
1596 if (isAllocatingOwnershipAttrCall(
Call)) {
1597 State = MallocBindRetVal(
C,
Call, State,
false);
1598 checkOwnershipAttr(State,
Call,
C);
1612 const Expr *Arg =
nullptr;
1614 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1615 Arg = CE->
getArg(IndexOfSizeArg);
1617 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1618 if (
NE->isArray()) {
1619 Arg = *
NE->getArraySize();
1624 assert(
false &&
"not a CallExpr or CXXNewExpr");
1629 RetVal = State->getSVal(
Call.getOriginExpr(),
C.getLocationContext());
1641 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1645 std::tie(TrueState, FalseState) =
1646 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal, Zero));
1648 if (TrueState && !FalseState) {
1649 SymbolRef Sym = RetVal->getAsLocSymbol();
1653 const RefState *RS = State->get<RegionState>(Sym);
1655 if (RS->isAllocated())
1656 return TrueState->set<RegionState>(Sym,
1657 RefState::getAllocatedOfSizeZero(RS));
1665 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1676 while (!PointeeType.isNull()) {
1677 Result = PointeeType;
1678 PointeeType = PointeeType->getPointeeType();
1691 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1697 for (
const auto *CtorParam : CtorD->
parameters()) {
1700 if (CtorParamPointeeT.
isNull())
1715 AllocationFamily Family)
const {
1720 const ParentMap &PM =
C.getLocationContext()->getParentMap();
1735 if (
Call.getOriginExpr()->isArray()) {
1736 if (
auto SizeEx =
NE->getArraySize())
1737 checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1738 AllocationFamily(AF_CXXNewArray));
1742 State = ProcessZeroAllocCheck(
C,
Call, 0, State,
Target);
1748 if (!
C.wasInlined) {
1751 AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1753 C.addTransition(State);
1763 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1764 return FirstSlot ==
"dataWithBytesNoCopy" ||
1765 FirstSlot ==
"initWithBytesNoCopy" ||
1766 FirstSlot ==
"initWithCharactersNoCopy";
1773 for (
unsigned i = 1; i < S.getNumArgs(); ++i)
1774 if (S.getNameForSlot(i) ==
"freeWhenDone")
1775 return !
Call.getArgSVal(i).isZeroConstant();
1777 return std::nullopt;
1792 if (
Call.hasNonZeroCallbackArg())
1795 bool IsKnownToBeAllocatedMemory;
1797 true, IsKnownToBeAllocatedMemory,
1798 AllocationFamily(AF_Malloc),
1801 C.addTransition(State);
1806 const OwnershipAttr *Att,
1811 auto attrClassName = Att->getModule()->getName();
1812 auto Family = AllocationFamily(AF_Custom, attrClassName);
1814 if (!Att->args().empty()) {
1815 return MallocMemAux(
C,
Call,
1816 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1825 bool isAlloca)
const {
1826 const Expr *CE =
Call.getOriginExpr();
1832 unsigned Count =
C.blockCount();
1837 return State->BindExpr(CE,
C.getLocationContext(), RetVal);
1844 AllocationFamily Family)
const {
1849 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
1852void MallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRef State,
1855 AllocationFamily Family)
const {
1856 if (
ExplodedNode *N =
C.generateNonFatalErrorNode(State,
this)) {
1857 if (!BT_TaintedAlloc)
1858 BT_TaintedAlloc.reset(
new BugType(CheckNames[CK_TaintedAllocChecker],
1859 "Tainted Memory Allocation",
1861 auto R = std::make_unique<PathSensitiveBugReport>(*BT_TaintedAlloc, Msg, N);
1862 for (
auto TaintedSym : TaintedSyms) {
1863 R->markInteresting(TaintedSym);
1865 C.emitReport(std::move(R));
1871 AllocationFamily Family)
const {
1872 if (!ChecksEnabled[CK_TaintedAllocChecker])
1874 std::vector<SymbolRef> TaintedSyms =
1876 if (TaintedSyms.empty())
1885 const llvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
1888 std::optional<NonLoc> SizeNL = SizeSVal.
getAs<
NonLoc>();
1889 auto Cmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
1893 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
1894 if (!StateTooLarge && StateNotTooLarge) {
1899 std::string
Callee =
"Memory allocation function";
1900 if (
Call.getCalleeIdentifier())
1901 Callee =
Call.getCalleeIdentifier()->getName().str();
1903 Callee +
" is called with a tainted (potentially attacker controlled) "
1904 "value. Make sure the value is bound checked.",
1905 State,
C, TaintedSyms, Family);
1911 AllocationFamily Family)
const {
1915 const Expr *CE =
Call.getOriginExpr();
1920 "Allocation functions must return a pointer");
1923 SVal RetVal = State->getSVal(CE,
C.getLocationContext());
1926 State = State->bindDefaultInitial(RetVal,
Init, LCtx);
1932 checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
1943 AllocationFamily Family,
1944 std::optional<SVal> RetVal) {
1950 RetVal = State->getSVal(
E,
C.getLocationContext());
1953 if (!RetVal->getAs<
Loc>())
1956 SymbolRef Sym = RetVal->getAsLocSymbol();
1964 return State->set<RegionState>(Sym, RefState::getAllocated(Family,
E));
1971 const OwnershipAttr *Att,
1976 auto attrClassName = Att->getModule()->getName();
1977 auto Family = AllocationFamily(AF_Custom, attrClassName);
1979 bool IsKnownToBeAllocated =
false;
1981 for (
const auto &Arg : Att->args()) {
1983 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
1984 Att->getOwnKind() == OwnershipAttr::Holds,
1985 IsKnownToBeAllocated, Family);
1995 bool Hold,
bool &IsKnownToBeAllocated,
1996 AllocationFamily Family,
1997 bool ReturnsNullOnFailure)
const {
2001 if (
Call.getNumArgs() < (
Num + 1))
2004 return FreeMemAux(
C,
Call.getArgExpr(
Num),
Call, State, Hold,
2005 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2012 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
2014 assert(*Ret &&
"We should not store the null return symbol");
2017 RetStatusSymbol = *Ret;
2025 const CallExpr *CE = dyn_cast<CallExpr>(
E);
2036 if (I->getOwnKind() != OwnershipAttr::Takes)
2039 os <<
", which takes ownership of '" << I->getModule()->
getName() <<
'\'';
2045 if (
const CallExpr *CE = dyn_cast<CallExpr>(
E)) {
2061 if (Msg->isInstanceMessage())
2065 Msg->getSelector().
print(os);
2069 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(
E)) {
2088 switch (Family.Kind) {
2095 case AF_CXXNewArray:
2098 case AF_IfNameIndex:
2099 os <<
"'if_nameindex()'";
2101 case AF_InnerBuffer:
2102 os <<
"container-specific allocator";
2105 os << Family.CustomName.value();
2109 assert(
false &&
"not a deallocation expression");
2114 switch (Family.Kind) {
2121 case AF_CXXNewArray:
2124 case AF_IfNameIndex:
2125 os <<
"'if_freenameindex()'";
2127 case AF_InnerBuffer:
2128 os <<
"container-specific deallocator";
2131 os <<
"function that takes ownership of '" << Family.CustomName.value()
2136 assert(
false &&
"not a deallocation expression");
2143 bool Hold,
bool &IsKnownToBeAllocated,
2144 AllocationFamily Family,
bool ReturnsNullOnFailure,
2145 std::optional<SVal> ArgValOpt)
const {
2150 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2151 if (!isa<DefinedOrUnknownSVal>(ArgVal))
2156 if (!isa<Loc>(location))
2161 std::tie(notNullState, nullState) = State->assume(location);
2162 if (nullState && !notNullState)
2171 const Expr *ParentExpr =
Call.getOriginExpr();
2190 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2191 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2199 if (isa<BlockDataRegion>(R)) {
2200 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2209 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
2215 if (isa<AllocaRegion>(R))
2218 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2231 const RefState *RsBase = State->get<RegionState>(SymBase);
2232 SymbolRef PreviousRetStatusSymbol =
nullptr;
2234 IsKnownToBeAllocated =
2235 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2240 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2246 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2248 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2249 SymBase, PreviousRetStatusSymbol);
2254 }
else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2255 RsBase->isEscaped()) {
2258 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2259 if (!DeallocMatchesAlloc) {
2261 RsBase, SymBase, Hold);
2268 if (Offset.isValid() &&
2269 !Offset.hasSymbolicOffset() &&
2270 Offset.getOffset() != 0) {
2271 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2280 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2286 State = State->remove<FreeReturnValue>(SymBase);
2290 if (ReturnsNullOnFailure) {
2291 SVal RetVal =
C.getSVal(ParentExpr);
2293 if (RetStatusSymbol) {
2294 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2295 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2303 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2308 State = State->invalidateRegions({location},
Call.getOriginExpr(),
2309 C.blockCount(),
C.getLocationContext(),
2315 return State->set<RegionState>(SymBase,
2316 RefState::getRelinquished(Family,
2319 return State->set<RegionState>(SymBase,
2320 RefState::getReleased(Family, ParentExpr));
2323std::optional<MallocChecker::CheckKind>
2324MallocChecker::getCheckIfTracked(AllocationFamily Family,
2325 bool IsALeakCheck)
const {
2326 switch (Family.Kind) {
2330 case AF_IfNameIndex: {
2331 if (ChecksEnabled[CK_MallocChecker])
2332 return CK_MallocChecker;
2333 return std::nullopt;
2336 case AF_CXXNewArray: {
2338 if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2339 return CK_NewDeleteLeaksChecker;
2342 if (ChecksEnabled[CK_NewDeleteChecker])
2343 return CK_NewDeleteChecker;
2345 return std::nullopt;
2347 case AF_InnerBuffer: {
2348 if (ChecksEnabled[CK_InnerPointerChecker])
2349 return CK_InnerPointerChecker;
2350 return std::nullopt;
2353 assert(
false &&
"no family");
2354 return std::nullopt;
2357 assert(
false &&
"unhandled family");
2358 return std::nullopt;
2361std::optional<MallocChecker::CheckKind>
2363 bool IsALeakCheck)
const {
2364 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2365 return CK_MallocChecker;
2367 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2369 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2372bool MallocChecker::SummarizeValue(raw_ostream &os,
SVal V) {
2373 if (std::optional<nonloc::ConcreteInt> IntVal =
2375 os <<
"an integer (" << IntVal->getValue() <<
")";
2376 else if (std::optional<loc::ConcreteInt> ConstAddr =
2378 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2380 os <<
"the address of the label '" <<
Label->getLabel()->getName() <<
"'";
2387bool MallocChecker::SummarizeRegion(raw_ostream &os,
2390 case MemRegion::FunctionCodeRegionKind: {
2391 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2393 os <<
"the address of the function '" << *FD <<
'\'';
2395 os <<
"the address of a function";
2398 case MemRegion::BlockCodeRegionKind:
2401 case MemRegion::BlockDataRegionKind:
2408 if (isa<StackLocalsSpaceRegion>(MS)) {
2409 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2417 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2419 os <<
"the address of a local stack variable";
2423 if (isa<StackArgumentsSpaceRegion>(MS)) {
2424 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2432 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2434 os <<
"the address of a parameter";
2438 if (isa<GlobalsSpaceRegion>(MS)) {
2439 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2448 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2450 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2452 os <<
"the address of a global variable";
2463 const Expr *DeallocExpr,
2464 AllocationFamily Family)
const {
2466 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2471 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2476 if (!BT_BadFree[*CheckKind])
2477 BT_BadFree[*CheckKind].reset(
new BugType(
2481 llvm::raw_svector_ostream os(buf);
2484 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2485 MR = ER->getSuperRegion();
2487 os <<
"Argument to ";
2489 os <<
"deallocator";
2492 bool Summarized = MR ? SummarizeRegion(os, MR)
2493 : SummarizeValue(os, ArgVal);
2495 os <<
", which is not memory allocated by ";
2497 os <<
"not memory allocated by ";
2501 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2503 R->markInteresting(MR);
2505 C.emitReport(std::move(R));
2512 std::optional<MallocChecker::CheckKind> CheckKind;
2514 if (ChecksEnabled[CK_MallocChecker])
2515 CheckKind = CK_MallocChecker;
2516 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2517 CheckKind = CK_MismatchedDeallocatorChecker;
2524 if (!BT_FreeAlloca[*CheckKind])
2525 BT_FreeAlloca[*CheckKind].reset(
new BugType(
2528 auto R = std::make_unique<PathSensitiveBugReport>(
2529 *BT_FreeAlloca[*CheckKind],
2530 "Memory allocated by 'alloca()' should not be deallocated", N);
2533 C.emitReport(std::move(R));
2539 const Expr *DeallocExpr,
2541 bool OwnershipTransferred)
const {
2543 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2549 if (!BT_MismatchedDealloc)
2550 BT_MismatchedDealloc.reset(
2551 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2555 llvm::raw_svector_ostream os(buf);
2557 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2559 llvm::raw_svector_ostream AllocOs(AllocBuf);
2561 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2563 if (OwnershipTransferred) {
2565 os << DeallocOs.str() <<
" cannot";
2569 os <<
" take ownership of memory";
2572 os <<
" allocated by " << AllocOs.str();
2576 os <<
" allocated by " << AllocOs.str();
2578 os <<
" should be deallocated by ";
2582 os <<
", not " << DeallocOs.str();
2587 auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2589 R->markInteresting(Sym);
2591 R->addVisitor<MallocBugVisitor>(Sym);
2592 C.emitReport(std::move(R));
2598 AllocationFamily Family,
2599 const Expr *AllocExpr)
const {
2601 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2606 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2614 if (!BT_OffsetFree[*CheckKind])
2615 BT_OffsetFree[*CheckKind].reset(
new BugType(
2619 llvm::raw_svector_ostream os(buf);
2621 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2624 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2627 assert((Offset.isValid() &&
2628 !Offset.hasSymbolicOffset() &&
2629 Offset.getOffset() != 0) &&
2630 "Only symbols with a valid offset can have offset free errors");
2632 int offsetBytes = Offset.getOffset() /
C.getASTContext().getCharWidth();
2634 os <<
"Argument to ";
2636 os <<
"deallocator";
2637 os <<
" is offset by "
2640 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2641 <<
" from the start of ";
2643 os <<
"memory allocated by " << AllocNameOs.str();
2645 os <<
"allocated memory";
2647 auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2651 C.emitReport(std::move(R));
2657 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2658 !ChecksEnabled[CK_InnerPointerChecker]) {
2663 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2668 if (!BT_UseFree[*CheckKind])
2669 BT_UseFree[*CheckKind].reset(
new BugType(
2672 AllocationFamily AF =
2673 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2675 auto R = std::make_unique<PathSensitiveBugReport>(
2676 *BT_UseFree[*CheckKind],
2677 AF.Kind == AF_InnerBuffer
2678 ?
"Inner pointer of container used after re/deallocation"
2679 :
"Use of memory after it is freed",
2682 R->markInteresting(Sym);
2684 R->addVisitor<MallocBugVisitor>(Sym);
2686 if (AF.Kind == AF_InnerBuffer)
2689 C.emitReport(std::move(R));
2697 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2702 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2707 if (!BT_DoubleFree[*CheckKind])
2708 BT_DoubleFree[*CheckKind].reset(
new BugType(
2711 auto R = std::make_unique<PathSensitiveBugReport>(
2712 *BT_DoubleFree[*CheckKind],
2713 (Released ?
"Attempt to free released memory"
2714 :
"Attempt to free non-owned memory"),
2717 R->markInteresting(Sym);
2719 R->markInteresting(PrevSym);
2720 R->addVisitor<MallocBugVisitor>(Sym);
2721 C.emitReport(std::move(R));
2727 if (!ChecksEnabled[CK_NewDeleteChecker]) {
2732 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2737 if (!BT_DoubleDelete)
2738 BT_DoubleDelete.reset(
new BugType(CheckNames[CK_NewDeleteChecker],
2742 auto R = std::make_unique<PathSensitiveBugReport>(
2743 *BT_DoubleDelete,
"Attempt to delete released memory", N);
2745 R->markInteresting(Sym);
2746 R->addVisitor<MallocBugVisitor>(Sym);
2747 C.emitReport(std::move(R));
2754 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2759 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2765 if (!BT_UseZerroAllocated[*CheckKind])
2766 BT_UseZerroAllocated[*CheckKind].reset(
2767 new BugType(CheckNames[*CheckKind],
"Use of zero allocated",
2770 auto R = std::make_unique<PathSensitiveBugReport>(
2771 *BT_UseZerroAllocated[*CheckKind],
2772 "Use of memory allocated with size zero", N);
2776 R->markInteresting(Sym);
2777 R->addVisitor<MallocBugVisitor>(Sym);
2779 C.emitReport(std::move(R));
2785 const Expr *FreeExpr,
2786 AllocationFamily Family)
const {
2787 if (!ChecksEnabled[CK_MallocChecker]) {
2792 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2797 if (!BT_BadFree[*CheckKind])
2798 BT_BadFree[*CheckKind].reset(
new BugType(
2802 llvm::raw_svector_ostream Os(Buf);
2805 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2806 MR = ER->getSuperRegion();
2808 Os <<
"Argument to ";
2810 Os <<
"deallocator";
2812 Os <<
" is a function pointer";
2814 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2816 R->markInteresting(MR);
2818 C.emitReport(std::move(R));
2825 AllocationFamily Family,
bool SuffixWithN)
const {
2829 const CallExpr *CE = cast<CallExpr>(
Call.getOriginExpr());
2837 SVal Arg0Val =
C.getSVal(arg0Expr);
2838 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2845 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2851 SVal TotalSize =
C.getSVal(Arg1);
2853 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2854 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2860 svalBuilder.makeIntValWithWidth(
2861 svalBuilder.getContext().getSizeType(), 0));
2864 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2866 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2869 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2870 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2874 if (PrtIsNull && !SizeIsZero) {
2881 if (PrtIsNull && SizeIsZero)
2886 bool IsKnownToBeAllocated =
false;
2895 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2900 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2907 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2908 if (ShouldFreeOnFail)
2909 Kind = OAR_FreeOnFailure;
2910 else if (!IsKnownToBeAllocated)
2911 Kind = OAR_DoNotTrackAfterFailure;
2915 SVal RetVal = stateRealloc->getSVal(CE,
C.getLocationContext());
2917 assert(FromPtr && ToPtr &&
2918 "By this point, FreeMemAux and MallocMemAux should have checked "
2919 "whether the argument or the return value is symbolic!");
2923 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2924 ReallocPair(FromPtr, Kind));
2926 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2927 return stateRealloc;
2938 if (
Call.getNumArgs() < 2)
2944 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2946 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State,
2947 AllocationFamily(AF_Malloc));
2950MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2957 const MemRegion *ReferenceRegion =
nullptr;
2961 if (!State->get<RegionState>(Sym))
2966 if (!ReferenceRegion) {
2967 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
2968 SVal Val = State->getSVal(MR);
2974 ReferenceRegion = MR;
2982 if (NContext == LeakContext ||
2988 return LeakInfo(AllocNode, ReferenceRegion);
2994 if (!ChecksEnabled[CK_MallocChecker] &&
2995 !ChecksEnabled[CK_NewDeleteLeaksChecker])
2998 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2999 assert(RS &&
"cannot leak an untracked symbol");
3000 AllocationFamily Family = RS->getAllocationFamily();
3002 if (Family.Kind == AF_Alloca)
3005 std::optional<MallocChecker::CheckKind> CheckKind =
3006 getCheckIfTracked(Family,
true);
3012 if (!BT_Leak[*CheckKind]) {
3018 BT_Leak[*CheckKind].reset(
new BugType(CheckNames[*CheckKind],
"Memory leak",
3029 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
3034 C.getSourceManager(),
3038 llvm::raw_svector_ostream os(buf);
3040 os <<
"Potential leak of memory pointed to by ";
3043 os <<
"Potential memory leak";
3046 auto R = std::make_unique<PathSensitiveBugReport>(
3047 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
3049 R->markInteresting(Sym);
3050 R->addVisitor<MallocBugVisitor>(Sym,
true);
3051 if (ShouldRegisterNoOwnershipChangeVisitor)
3052 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
3053 C.emitReport(std::move(R));
3056void MallocChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
3060 RegionStateTy OldRS = state->get<RegionState>();
3061 RegionStateTy::Factory &F = state->get_context<RegionState>();
3063 RegionStateTy RS = OldRS;
3065 for (
auto [Sym, State] : RS) {
3066 if (SymReaper.
isDead(Sym)) {
3067 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3068 Errors.push_back(Sym);
3070 RS = F.remove(RS, Sym);
3076 assert(state->get<ReallocPairs>() ==
3077 C.getState()->get<ReallocPairs>());
3078 assert(state->get<FreeReturnValue>() ==
3079 C.getState()->get<FreeReturnValue>());
3084 ReallocPairsTy RP = state->get<ReallocPairs>();
3085 for (
auto [Sym, ReallocPair] : RP) {
3086 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
3087 state = state->remove<ReallocPairs>(Sym);
3092 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3093 for (
auto [Sym, RetSym] : FR) {
3094 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
3095 state = state->remove<FreeReturnValue>(Sym);
3101 if (!Errors.empty()) {
3103 N =
C.generateNonFatalErrorNode(
C.getState(), &Tag);
3106 HandleLeak(Sym, N,
C);
3111 C.addTransition(state->set<RegionState>(RS), N);
3116 if (
const auto *PostFN = PostFnMap.lookup(
Call)) {
3117 (*PostFN)(
this,
C.getState(),
Call,
C);
3125 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3128 if (!ChecksEnabled[CK_NewDeleteChecker])
3136 bool IsKnownToBeAllocated;
3139 false, IsKnownToBeAllocated,
3140 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3142 C.addTransition(State);
3146 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3147 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3148 if (!Sym || checkDoubleDelete(Sym,
C))
3154 if (
const auto *PreFN = PreFnMap.lookup(
Call)) {
3155 (*PreFN)(
this,
C.getState(),
Call,
C);
3165 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(
Call))
3171 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3172 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3177 for (
unsigned I = 0,
E =
Call.getNumArgs(); I !=
E; ++I) {
3179 if (isa<Loc>(ArgSVal)) {
3183 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3189void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3191 checkEscapeOnReturn(S,
C);
3197void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3199 checkEscapeOnReturn(S,
C);
3202void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3207 const Expr *
E = S->getRetValue();
3213 SVal RetVal =
C.getSVal(
E);
3220 if (isa<FieldRegion, ElementRegion>(MR))
3223 Sym = BMR->getSymbol();
3227 checkUseAfterFree(Sym,
C,
E);
3233void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3243 cast<BlockDataRegion>(
C.getSVal(BE).getAsRegion());
3246 if (ReferencedVars.empty())
3253 for (
const auto &Var : ReferencedVars) {
3254 const VarRegion *VR = Var.getCapturedRegion();
3258 Regions.push_back(VR);
3262 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3263 C.addTransition(state);
3268 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3269 return (RS && RS->isReleased());
3272bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3274 if (
Call.getNumArgs() == 0)
3277 StringRef FunctionStr =
"";
3278 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3280 if (Body->getBeginLoc().isValid())
3284 C.getSourceManager(),
C.getLangOpts());
3287 if (!FunctionStr.contains(
"__isl_"))
3292 for (
const Expr *Arg : cast<CallExpr>(
Call.getOriginExpr())->arguments())
3293 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3294 if (
const RefState *RS = State->get<RegionState>(Sym))
3295 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3297 C.addTransition(State);
3302 const Stmt *S)
const {
3305 HandleUseAfterFree(
C, S->getSourceRange(), Sym);
3313 const Stmt *S)
const {
3316 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3317 if (RS->isAllocatedOfSizeZero())
3318 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3320 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3321 HandleUseZeroAlloc(
C, S->getSourceRange(), Sym);
3328 HandleDoubleDelete(
C, Sym);
3335void MallocChecker::checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
3339 checkUseAfterFree(Sym,
C, S);
3340 checkUseZeroAllocated(Sym,
C, S);
3348 bool Assumption)
const {
3349 RegionStateTy RS = state->get<RegionState>();
3350 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3355 state = state->remove<RegionState>(Sym);
3360 ReallocPairsTy RP = state->get<ReallocPairs>();
3361 for (
auto [Sym, ReallocPair] : RP) {
3368 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3369 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3370 if (RS->isReleased()) {
3371 switch (ReallocPair.Kind) {
3372 case OAR_ToBeFreedAfterFailure:
3373 state = state->set<RegionState>(ReallocSym,
3374 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3376 case OAR_DoNotTrackAfterFailure:
3377 state = state->remove<RegionState>(ReallocSym);
3380 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3384 state = state->remove<ReallocPairs>(Sym);
3390bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3395 EscapingSymbol =
nullptr;
3401 if (!isa<SimpleFunctionCall, ObjCMethodCall>(
Call))
3408 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3421 return *FreeWhenDone;
3427 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3428 if (FirstSlot.ends_with(
"NoCopy"))
3435 if (FirstSlot.starts_with(
"addPointer") ||
3436 FirstSlot.starts_with(
"insertPointer") ||
3437 FirstSlot.starts_with(
"replacePointer") ||
3438 FirstSlot ==
"valueWithPointer") {
3445 if (Msg->getMethodFamily() ==
OMF_init) {
3446 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3462 if (isMemCall(*
Call))
3466 if (!
Call->isInSystemHeader())
3473 StringRef FName = II->
getName();
3477 if (FName.ends_with(
"NoCopy")) {
3481 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3482 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3483 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3484 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3485 if (DeallocatorName ==
"kCFAllocatorNull")
3496 if (FName ==
"funopen")
3497 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3503 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3504 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3505 if (
Call->getNumArgs() >= 1) {
3506 const Expr *ArgE =
Call->getArgExpr(0)->IgnoreParenCasts();
3507 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3508 if (
const VarDecl *
D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3519 if (FName ==
"CGBitmapContextCreate" ||
3520 FName ==
"CGBitmapContextCreateWithData" ||
3521 FName ==
"CVPixelBufferCreateWithBytes" ||
3522 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3523 FName ==
"OSAtomicEnqueue") {
3527 if (FName ==
"postEvent" &&
3532 if (FName ==
"connectImpl" &&
3537 if (FName ==
"singleShotImpl" &&
3546 if (
Call->argumentsMayEscape())
3558 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3567 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3572 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3573 RS->getAllocationFamily().Kind == AF_CXXNew);
3579 bool IsConstPointerEscape)
const {
3584 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3591 if (EscapingSymbol && EscapingSymbol != sym)
3594 if (
const RefState *RS = State->get<RegionState>(sym))
3595 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3597 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3603 SVal ArgVal)
const {
3604 if (!KernelZeroSizePtrValue)
3605 KernelZeroSizePtrValue =
3608 const llvm::APSInt *ArgValKnown =
3609 C.getSValBuilder().getKnownValue(State, ArgVal);
3610 return ArgValKnown && *KernelZeroSizePtrValue &&
3611 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3616 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3617 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3619 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3621 if (!currMap.lookup(sym))
3631 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3632 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3633 N.contains_insensitive(
"intrusive") ||
3634 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3648 const RefState *RSCurr = state->get<RegionState>(Sym);
3649 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3654 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3667 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
3669 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3672 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3673 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3679 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
3682 if (
const auto *MD =
3702 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3704 llvm::raw_svector_ostream OS(Buf);
3707 if (isAllocated(RSCurr, RSPrev, S)) {
3708 Msg =
"Memory is allocated";
3709 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3710 Sym,
"Returned allocated memory");
3712 const auto Family = RSCurr->getAllocationFamily();
3713 switch (Family.Kind) {
3718 case AF_CXXNewArray:
3719 case AF_IfNameIndex:
3720 Msg =
"Memory is released";
3721 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3722 Sym,
"Returning; memory was released");
3724 case AF_InnerBuffer: {
3727 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
3729 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
3732 OS <<
"deallocated by call to destructor";
3733 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3734 Sym,
"Returning; inner buffer was deallocated");
3736 OS <<
"reallocated by call to '";
3737 const Stmt *S = RSCurr->getStmt();
3738 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3739 OS << MemCallE->getMethodDecl()->getDeclName();
3740 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3741 OS << OpCallE->getDirectCallee()->getDeclName();
3742 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
3745 CEMgr.getSimpleCall(CallE, state, CurrentLC, {
nullptr, 0});
3746 if (
const auto *
D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
3747 OS <<
D->getDeclName();
3752 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3753 Sym,
"Returning; inner buffer was reallocated");
3759 assert(
false &&
"Unhandled allocation family!");
3764 assert(!ReleaseFunctionLC &&
"There should be only one release point");
3771 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
3811 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
3812 Msg =
"Memory ownership is transferred";
3813 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
3814 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3815 Mode = ReallocationFailed;
3816 Msg =
"Reallocation failed";
3817 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3818 Sym,
"Reallocation failed");
3822 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3823 "We only support one failed realloc at a time.");
3825 FailedReallocSymbol = sym;
3830 }
else if (Mode == ReallocationFailed) {
3831 assert(FailedReallocSymbol &&
"No symbol to look for.");
3834 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3836 Msg =
"Attempt to reallocate memory";
3837 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3838 Sym,
"Returned reallocated memory");
3839 FailedReallocSymbol =
nullptr;
3854 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
3865 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
3870void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
3871 const char *NL,
const char *Sep)
const {
3873 RegionStateTy RS = State->get<RegionState>();
3875 if (!RS.isEmpty()) {
3876 Out << Sep <<
"MallocChecker :" << NL;
3877 for (
auto [Sym,
Data] : RS) {
3878 const RefState *RefS = State->get<RegionState>(Sym);
3879 AllocationFamily Family = RefS->getAllocationFamily();
3880 std::optional<MallocChecker::CheckKind> CheckKind =
3881 getCheckIfTracked(Family);
3883 CheckKind = getCheckIfTracked(Family,
true);
3889 Out <<
" (" << CheckNames[*CheckKind].getName() <<
")";
3897namespace allocation_state {
3901 AllocationFamily Family(AF_InnerBuffer);
3902 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3912 MallocChecker *checker = mgr.
getChecker<MallocChecker>();
3913 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] =
true;
3914 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3920 checker->ShouldIncludeOwnershipAnnotatedFunctions =
3922 checker->ShouldRegisterNoOwnershipChangeVisitor =
3924 checker,
"AddNoOwnershipChangeNotes");
3927bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
3931#define REGISTER_CHECKER(name) \
3932 void ento::register##name(CheckerManager &mgr) { \
3933 MallocChecker *checker = mgr.getChecker<MallocChecker>(); \
3934 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
3935 checker->CheckNames[MallocChecker::CK_##name] = \
3936 mgr.getCurrentCheckerName(); \
3939 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
enum clang::sema::@1718::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)
static bool isStandardNew(const FunctionDecl *FD)
#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 isStandardDelete(const FunctionDecl *FD)
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static bool isStandardNewDelete(const T &FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
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 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.
APSIntPtr 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)
DefinedSVal getConjuredHeapSymbolVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Conjure a symbol representing heap allocated memory region.
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...
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.
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent)
Set the dynamic extent Extent of the region MR.
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.
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.