;
94using namespacestd::placeholders;
106enumAllocationFamilyKind {
117structAllocationFamily {
118AllocationFamilyKind
Kind;
119std::optional<StringRef> CustomName;
121 explicitAllocationFamily(AllocationFamilyKind AKind,
122std::optional<StringRef> Name = std::nullopt)
123:
Kind(AKind), CustomName(Name) {
124assert((Kind != AF_Custom || CustomName.has_value()) &&
125 "Custom family must specify also the name");
128 if(Kind == AF_Custom && CustomName.value() ==
"malloc") {
130CustomName = std::nullopt;
135 returnstd::tie(Kind, CustomName) == std::tie(
Other.Kind,
Other.CustomName);
139 return!(*
this==
Other);
142 voidProfile(llvm::FoldingSetNodeID &ID)
const{
143 ID.AddInteger(Kind);
145 if(Kind == AF_Custom)
146 ID.AddString(CustomName.value());
191AllocationFamily Family;
193RefState(Kind k,
const Stmt*
s, AllocationFamily family)
194: S(
s), K(k), Family(family) {
195assert(family.Kind != AF_None);
199 boolisAllocated()
const{
returnK == Allocated; }
200 boolisAllocatedOfSizeZero()
const{
returnK == AllocatedOfSizeZero; }
201 bool isReleased()
const{
returnK == Released; }
202 boolisRelinquished()
const{
returnK == Relinquished; }
203 boolisEscaped()
const{
returnK == Escaped; }
204AllocationFamily getAllocationFamily()
const{
returnFamily; }
205 const Stmt*getStmt()
const{
returnS; }
208 returnK ==
X.K && S ==
X.S && Family ==
X.Family;
211 staticRefState getAllocated(AllocationFamily family,
const Stmt*
s) {
212 returnRefState(Allocated,
s, family);
214 staticRefState getAllocatedOfSizeZero(
constRefState *RS) {
215 returnRefState(AllocatedOfSizeZero, RS->getStmt(),
216RS->getAllocationFamily());
218 staticRefState getReleased(AllocationFamily family,
const Stmt*
s) {
219 returnRefState(Released,
s, family);
221 staticRefState getRelinquished(AllocationFamily family,
const Stmt*
s) {
222 returnRefState(Relinquished,
s, family);
224 staticRefState getEscaped(
constRefState *RS) {
225 returnRefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
228 voidProfile(llvm::FoldingSetNodeID &ID)
const{
234LLVM_DUMP_METHOD
void dump(raw_ostream &OS)
const{
236#define CASE(ID) case ID: OS << #ID; break; 238 CASE(AllocatedOfSizeZero)
245LLVM_DUMP_METHOD
void dump()
const{
dump(llvm::errs()); }
260AllocationFamily Family,
261std::optional<SVal> RetVal = std::nullopt);
275enumOwnershipAfterReallocKind {
277OAR_ToBeFreedAfterFailure,
287OAR_DoNotTrackAfterFailure
300OwnershipAfterReallocKind
Kind;
302ReallocPair(
SymbolRefS, OwnershipAfterReallocKind K)
303: ReallocatedSym(S),
Kind(K) {}
304 voidProfile(llvm::FoldingSetNodeID &ID)
const{
305 ID.AddInteger(Kind);
306 ID.AddPointer(ReallocatedSym);
309 returnReallocatedSym ==
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,
346check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
347check::EndFunction, check::PreCall, check::PostCall,
348eval::Call, check::NewAllocator,
349check::PostStmt<BlockExpr>, check::PostObjCMessage,
350check::Location, eval::Assume> {
356 boolShouldIncludeOwnershipAnnotatedFunctions =
false;
358 boolShouldRegisterNoOwnershipChangeVisitor =
false;
368CK_NewDeleteLeaksChecker,
369CK_MismatchedDeallocatorChecker,
370CK_InnerPointerChecker,
371CK_TaintedAllocChecker,
375 usingLeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
377 boolChecksEnabled[CK_NumCheckKinds] = {
false};
390 boolAssumption)
const;
391 voidcheckLocation(
SVall,
boolisLoad,
const Stmt*S,
404 const char*NL,
const char*Sep)
const override;
407 mutablestd::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];
408 mutablestd::unique_ptr<BugType> BT_DoubleDelete;
409 mutablestd::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];
410 mutablestd::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];
411 mutablestd::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
412 mutablestd::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
413 mutablestd::unique_ptr<BugType> BT_MismatchedDealloc;
414 mutablestd::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
415 mutablestd::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
416 mutablestd::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 boolisFreeingOwnershipAttrCall(
const CallEvent&
Call);
473 static boolisAllocatingOwnershipAttrCall(
const CallEvent&
Call);
475 friend classNoMemOwnershipChangeVisitor;
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},
512std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
513{{CDM::CLibrary, {
"reallocf"}, 2},
514std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
true)},
515{{CDM::CLibrary, {
"g_realloc"}, 2},
516std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
517{{CDM::CLibrary, {
"g_try_realloc"}, 2},
518std::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},
525 boolhasOwnershipTakesHolds(
const CallEvent&
Call)
const;
528AllocationFamily Family)
const;
532AllocationFamily Family)
const;
535 mutablestd::optional<uint64_t> KernelZeroFlagVal;
537 usingKernelZeroSizePtrValueTy = std::optional<int>;
542 mutablestd::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
548AllocationFamily Family)
const;
561std::optional<SVal> RetVal = std::nullopt);
592 boolisAlloca)
const;
619AllocationFamily Family)
const;
623[[nodiscard]] std::optional<ProgramStateRef>
646 constOwnershipAttr *Att,
670 unsigned Num,
boolHold,
bool&IsKnownToBeAllocated,
671AllocationFamily Family,
boolReturnsNullOnFailure =
false)
const;
697AllocationFamily Family,
boolReturnsNullOnFailure =
false,
698std::optional<SVal> ArgValOpt = {})
const;
716 boolSuffixWithN =
false)
const;
725 const Expr*BlockBytes);
738 boolsuppressDeallocationsInSuspiciousContexts(
const CallEvent&
Call,
747 const Stmt*S)
const;
762 boolmayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent*
Call,
771 boolIsConstPointerEscape)
const;
780std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
781 boolIsALeakCheck =
false)
const;
784 boolIsALeakCheck =
false)
const;
786 static boolSummarizeValue(raw_ostream &os,
SVal V);
787 static boolSummarizeRegion(raw_ostream &os,
const MemRegion*MR);
790 const Expr*DeallocExpr,
791AllocationFamily Family)
const;
797 const Expr*DeallocExpr,
constRefState *RS,
798 SymbolRefSym,
boolOwnershipTransferred)
const;
801 const Expr*DeallocExpr, AllocationFamily Family,
802 const Expr*AllocExpr =
nullptr)
const;
816 const Expr*FreeExpr,
817AllocationFamily Family)
const;
846 boolisFreeingCallAsWritten(
const CallExpr&
Call)
const{
847 const auto*MallocChk =
static_cast<constMallocChecker *
>(&
Checker);
848 if(MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
849MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
852 if(
const auto*
Func=
853llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
854 returnMallocChecker::isFreeingOwnershipAttrCall(
Func);
861 returnCallEnterState->get<RegionState>(Sym) !=
862CallExitEndState->get<RegionState>(Sym);
869 booldoesFnIntendToHandleOwnership(
const Decl*Callee,
871 const FunctionDecl*FD = dyn_cast<FunctionDecl>(Callee);
890 if(
const auto*
Call= Match.getNodeAs<
CallExpr>(
"call"))
891 if(isFreeingCallAsWritten(*
Call))
903N->getState()->getStateManager().getContext().getSourceManager());
904 returnstd::make_shared<PathDiagnosticEventPiece>(
905L,
"Returning without deallocating memory or storing the pointer for " 906 "later deallocation");
913 voidProfile(llvm::FoldingSetNodeID &ID)
const override{
915 ID.AddPointer(&Tag);
932 enumNotificationMode {
Normal, ReallocationFailed };
938NotificationMode Mode;
950MallocBugVisitor(
SymbolRefS,
boolisLeak =
false)
951: Sym(S), Mode(
Normal), FailedReallocSymbol(nullptr),
952ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}
954 static void*getTag() {
959 void Profile(llvm::FoldingSetNodeID &ID)
const override{
960 ID.AddPointer(getTag());
965 static inline boolisAllocated(
constRefState *RSCurr,
constRefState *RSPrev,
967 return(isa_and_nonnull<CallExpr, CXXNewExpr>(
Stmt) &&
969(RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
971!(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
976 static inline bool isReleased(
constRefState *RSCurr,
constRefState *RSPrev,
979(RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
980assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(
Stmt)) ||
981(!
Stmt&& RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
986 static inline boolisRelinquished(
constRefState *RSCurr,
987 constRefState *RSPrev,
const Stmt*
Stmt) {
989isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(
Stmt) &&
990(RSCurr && RSCurr->isRelinquished()) &&
991(!RSPrev || !RSPrev->isRelinquished()));
998 static inline boolhasReallocFailed(
constRefState *RSCurr,
999 constRefState *RSPrev,
1001 return((!isa_and_nonnull<CallExpr>(
Stmt)) &&
1003(RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1005!(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1020 returnstd::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1025 classStackHintGeneratorForReallocationFailed
1028StackHintGeneratorForReallocationFailed(
SymbolRefS, StringRef M)
1031std::string getMessageForArg(
const Expr*ArgE,
unsignedArgIndex)
override{
1036llvm::raw_svector_ostream os(buf);
1038os <<
"Reallocation of "<< ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1039<<
" parameter failed";
1041 returnstd::string(os.str());
1045 return "Reallocation of returned value failed";
1064state = state->remove<RegionState>(sym);
1075 if(Kind != OO_New && Kind != OO_Array_New)
1091 if(Kind != OO_Delete && Kind != OO_Array_Delete)
1094 boolHasBody = FD->
hasBody();
1102 returnL.
isInvalid() || (!HasBody &&
SM.isInSystemHeader(L));
1109boolMallocChecker::isFreeingOwnershipAttrCall(
const CallEvent&
Call) {
1110 const auto*
Func= dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1112 return Func&& isFreeingOwnershipAttrCall(
Func);
1115boolMallocChecker::isFreeingOwnershipAttrCall(
const FunctionDecl*
Func) {
1116 if(
Func->hasAttrs()) {
1117 for(
const auto*I :
Func->specific_attrs<OwnershipAttr>()) {
1118OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1119 if(OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1126boolMallocChecker::isFreeingCall(
const CallEvent&
Call)
const{
1127 if(FreeingMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1130 returnisFreeingOwnershipAttrCall(
Call);
1133boolMallocChecker::isAllocatingOwnershipAttrCall(
const CallEvent&
Call) {
1134 const auto*
Func= dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1136 return Func&& isAllocatingOwnershipAttrCall(
Func);
1139boolMallocChecker::isAllocatingOwnershipAttrCall(
const FunctionDecl*
Func) {
1140 for(
const auto*I :
Func->specific_attrs<OwnershipAttr>()) {
1141 if(I->getOwnKind() == OwnershipAttr::Returns)
1148boolMallocChecker::isMemCall(
const CallEvent&
Call)
const{
1149 if(FreeingMemFnMap.lookup(
Call) || AllocatingMemFnMap.lookup(
Call) ||
1150AllocaMemFnMap.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 casellvm::Triple::FreeBSD:
1185KernelZeroFlagVal = 0x0100;
1187 casellvm::Triple::NetBSD:
1188KernelZeroFlagVal = 0x0002;
1190 casellvm::Triple::OpenBSD:
1191KernelZeroFlagVal = 0x0008;
1193 casellvm::Triple::Linux:
1195KernelZeroFlagVal = 0x8000;
1203 returnstd::nullopt;
1210 if(
Call.getNumArgs() < 2)
1211 returnstd::nullopt;
1213 const Expr*FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1214 const SVal V=
C.getSVal(FlagsEx);
1215 if(!isa<NonLoc>(
V)) {
1218 returnstd::nullopt;
1222 NonLocZeroFlag =
C.getSValBuilder()
1223.makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1225 SValMaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1229 returnstd::nullopt;
1234std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1237 if(TrueState && !FalseState) {
1238 SValZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1239 returnMallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1240AllocationFamily(AF_Malloc));
1243 returnstd::nullopt;
1247 const Expr*BlockBytes) {
1249 SValBlocksVal =
C.getSVal(Blocks);
1250 SValBlockBytesVal =
C.getSVal(BlockBytes);
1252 SValTotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1261AllocationFamily(AF_Malloc));
1262State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1263 C.addTransition(State);
1269std::optional<ProgramStateRef> MaybeState =
1270performKernelMalloc(
Call,
C, State);
1272State = *MaybeState;
1275AllocationFamily(AF_Malloc));
1276 C.addTransition(State);
1303 boolShouldFreeOnFail)
const{
1312State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1313AllocationFamily(AF_Malloc));
1314State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1315 C.addTransition(State);
1320State = CallocMem(
C,
Call, State);
1321State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1322State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1323 C.addTransition(State);
1328 boolIsKnownToBeAllocatedMemory =
false;
1329 if(suppressDeallocationsInSuspiciousContexts(
Call,
C))
1331State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1332AllocationFamily(AF_Malloc));
1333 C.addTransition(State);
1339AllocationFamily(AF_Alloca));
1340State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1341 C.addTransition(State);
1346 const auto*CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1350AllocationFamily(AF_Malloc));
1352 C.addTransition(State);
1361AllocationFamily(AF_IfNameIndex));
1363 C.addTransition(State);
1369 boolIsKnownToBeAllocatedMemory =
false;
1370State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1371AllocationFamily(AF_IfNameIndex));
1372 C.addTransition(State);
1378 boolIsKnownToBeAllocatedMemory =
false;
1379 const auto*CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1393AllocationFamily(AF_CXXNew));
1394State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1398AllocationFamily(AF_CXXNewArray));
1399State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1402State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1403AllocationFamily(AF_CXXNew));
1405 caseOO_Array_Delete:
1406State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1407AllocationFamily(AF_CXXNewArray));
1410assert(
false&&
"not a new/delete operator");
1414 C.addTransition(State);
1421State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1422AllocationFamily(AF_Malloc));
1423State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1424 C.addTransition(State);
1430AllocationFamily(AF_Malloc));
1431State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1432 C.addTransition(State);
1438 SValTotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1439State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1440AllocationFamily(AF_Malloc));
1441State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1442State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1443 C.addTransition(State);
1450 SValTotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1451State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1452AllocationFamily(AF_Malloc));
1453State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1454State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1455 C.addTransition(State);
1460assert(FD &&
"a CallDescription cannot match a call without a Decl");
1479 boolIsKnownToBeAllocated =
false;
1480State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1481IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1484 C.addTransition(State);
1496 const CallExpr*CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1500 const autoLinePtr =
1504 if(!LinePtr || !Size || !LinePtr->getAsRegion())
1509AllocationFamily(AF_Malloc), *LinePtr));
1514State = ReallocMemAux(
C,
Call,
false, State,
1515AllocationFamily(AF_Malloc),
1517State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1518State = ProcessZeroAllocCheck(
C,
Call, 2, State);
1519 C.addTransition(State);
1525 const auto*CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1531 if(ShouldIncludeOwnershipAnnotatedFunctions ||
1532ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1537 switch(I->getOwnKind()) {
1538 caseOwnershipAttr::Returns:
1539State = MallocMemReturnsAttr(
C,
Call, I, State);
1541 caseOwnershipAttr::Takes:
1542 caseOwnershipAttr::Holds:
1543State = FreeMemAttr(
C,
Call, I, State);
1548 C.addTransition(State);
1552 if(!
Call.getOriginExpr())
1557 if(
constCheckFn *Callback = FreeingMemFnMap.lookup(
Call)) {
1558(*Callback)(
this, State,
Call,
C);
1562 if(
constCheckFn *Callback = AllocatingMemFnMap.lookup(
Call)) {
1563State = MallocBindRetVal(
C,
Call, State,
false);
1564(*Callback)(
this, State,
Call,
C);
1568 if(
constCheckFn *Callback = ReallocatingMemFnMap.lookup(
Call)) {
1569State = MallocBindRetVal(
C,
Call, State,
false);
1570(*Callback)(
this, State,
Call,
C);
1575State = MallocBindRetVal(
C,
Call, State,
false);
1576checkCXXNewOrCXXDelete(State,
Call,
C);
1581checkCXXNewOrCXXDelete(State,
Call,
C);
1585 if(
constCheckFn *Callback = AllocaMemFnMap.lookup(
Call)) {
1586State = MallocBindRetVal(
C,
Call, State,
true);
1587(*Callback)(
this, State,
Call,
C);
1591 if(isFreeingOwnershipAttrCall(
Call)) {
1592checkOwnershipAttr(State,
Call,
C);
1596 if(isAllocatingOwnershipAttrCall(
Call)) {
1597State = MallocBindRetVal(
C,
Call, State,
false);
1598checkOwnershipAttr(State,
Call,
C);
1612 const Expr*Arg =
nullptr;
1614 if(
const CallExpr*CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1615Arg = CE->
getArg(IndexOfSizeArg);
1617dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1618 if(
NE->isArray()) {
1619Arg = *
NE->getArraySize();
1624assert(
false&&
"not a CallExpr or CXXNewExpr");
1629RetVal = State->getSVal(
Call.getOriginExpr(),
C.getLocationContext());
1634State->getSVal(Arg,
Call.getLocationContext()).getAs<
DefinedSVal>();
1641 SValBuilder&SvalBuilder = State->getStateManager().getSValBuilder();
1645std::tie(TrueState, FalseState) =
1646State->assume(SvalBuilder.
evalEQ(State, *DefArgVal, Zero));
1648 if(TrueState && !FalseState) {
1649 SymbolRefSym = RetVal->getAsLocSymbol();
1653 constRefState *RS = State->get<RegionState>(Sym);
1655 if(RS->isAllocated())
1656 returnTrueState->set<RegionState>(Sym,
1657RefState::getAllocatedOfSizeZero(RS));
1665 returnTrueState->add<ReallocSizeZeroSymbols>(Sym);
1676 while(!PointeeType.isNull()) {
1677Result = PointeeType;
1678PointeeType = PointeeType->getPointeeType();
1691 if(!NE->getAllocatedType()->getAsCXXRecordDecl())
1697 for(
const auto*CtorParam : CtorD->
parameters()) {
1700 if(CtorParamPointeeT.
isNull())
1715AllocationFamily Family)
const{
1720 const ParentMap&PM =
C.getLocationContext()->getParentMap();
1735 if(
Call.getOriginExpr()->isArray()) {
1736 if(
autoSizeEx =
NE->getArraySize())
1737checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1738AllocationFamily(AF_CXXNewArray));
1742State = ProcessZeroAllocCheck(
C,
Call, 0, State,
Target);
1748 if(!
C.wasInlined) {
1751AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1753 C.addTransition(State);
1763StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1764 returnFirstSlot ==
"dataWithBytesNoCopy"||
1765FirstSlot ==
"initWithBytesNoCopy"||
1766FirstSlot ==
"initWithCharactersNoCopy";
1773 for(
unsignedi = 1; i < S.getNumArgs(); ++i)
1774 if(S.getNameForSlot(i) ==
"freeWhenDone")
1775 return!
Call.getArgSVal(i).isZeroConstant();
1777 returnstd::nullopt;
1792 if(
Call.hasNonZeroCallbackArg())
1795 boolIsKnownToBeAllocatedMemory;
1797 true, IsKnownToBeAllocatedMemory,
1798AllocationFamily(AF_Malloc),
1801 C.addTransition(State);
1806 constOwnershipAttr *Att,
1811 autoattrClassName = Att->getModule()->getName();
1812 autoFamily = AllocationFamily(AF_Custom, attrClassName);
1814 if(!Att->args().empty()) {
1815 returnMallocMemAux(
C,
Call,
1816 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1825 boolisAlloca)
const{
1826 const Expr*CE =
Call.getOriginExpr();
1832 unsignedCount =
C.blockCount();
1837 returnState->BindExpr(CE,
C.getLocationContext(), RetVal);
1844AllocationFamily Family)
const{
1849 returnMallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
1852voidMallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRefState,
1855AllocationFamily Family)
const{
1856 if(
ExplodedNode*N =
C.generateNonFatalErrorNode(State,
this)) {
1857 if(!BT_TaintedAlloc)
1858BT_TaintedAlloc.reset(
new BugType(CheckNames[CK_TaintedAllocChecker],
1859 "Tainted Memory Allocation",
1861 autoR = std::make_unique<PathSensitiveBugReport>(*BT_TaintedAlloc, Msg, N);
1862 for(
autoTaintedSym : TaintedSyms) {
1863R->markInteresting(TaintedSym);
1865 C.emitReport(std::move(R));
1871AllocationFamily Family)
const{
1872 if(!ChecksEnabled[CK_TaintedAllocChecker])
1874std::vector<SymbolRef> TaintedSyms =
1876 if(TaintedSyms.empty())
1885 constllvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
1888std::optional<NonLoc> SizeNL = SizeSVal.
getAs<
NonLoc>();
1889 autoCmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
1893 auto[StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
1894 if(!StateTooLarge && StateNotTooLarge) {
1899std::string
Callee=
"Memory allocation function";
1900 if(
Call.getCalleeIdentifier())
1901Callee =
Call.getCalleeIdentifier()->getName().str();
1903Callee +
" is called with a tainted (potentially attacker controlled) " 1904 "value. Make sure the value is bound checked.",
1905State,
C, TaintedSyms, Family);
1911AllocationFamily Family)
const{
1915 const Expr*CE =
Call.getOriginExpr();
1920 "Allocation functions must return a pointer");
1923 SValRetVal = State->getSVal(CE,
C.getLocationContext());
1926State = State->bindDefaultInitial(RetVal,
Init, LCtx);
1929 if(
Size.isUndef())
1932checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
1943AllocationFamily Family,
1944std::optional<SVal> RetVal) {
1950RetVal = State->getSVal(
E,
C.getLocationContext());
1953 if(!RetVal->getAs<
Loc>())
1956 SymbolRefSym = RetVal->getAsLocSymbol();
1964 returnState->set<RegionState>(Sym, RefState::getAllocated(Family,
E));
1971 constOwnershipAttr *Att,
1976 autoattrClassName = Att->getModule()->getName();
1977 autoFamily = AllocationFamily(AF_Custom, attrClassName);
1979 boolIsKnownToBeAllocated =
false;
1981 for(
const auto&Arg : Att->args()) {
1983FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
1984Att->getOwnKind() == OwnershipAttr::Holds,
1985IsKnownToBeAllocated, Family);
1995 boolHold,
bool&IsKnownToBeAllocated,
1996AllocationFamily Family,
1997 boolReturnsNullOnFailure)
const{
2001 if(
Call.getNumArgs() < (
Num+ 1))
2004 returnFreeMemAux(
C,
Call.getArgExpr(
Num),
Call, State, Hold,
2005IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2012 const SymbolRef*Ret = State->get<FreeReturnValue>(Sym);
2014assert(*Ret &&
"We should not store the null return symbol");
2017RetStatusSymbol = *Ret;
2025 const CallExpr*CE = dyn_cast<CallExpr>(
E);
2036 if(I->getOwnKind() != OwnershipAttr::Takes)
2039os <<
", which takes ownership of '"<< I->getModule()->
getName() <<
'\'';
2045 if(
const CallExpr*CE = dyn_cast<CallExpr>(
E)) {
2061 if(Msg->isInstanceMessage())
2065Msg->getSelector().
print(os);
2069 if(
const CXXNewExpr*NE = dyn_cast<CXXNewExpr>(
E)) {
2088 switch(Family.Kind) {
2090os <<
"'malloc()'";
2095 caseAF_CXXNewArray:
2098 caseAF_IfNameIndex:
2099os <<
"'if_nameindex()'";
2101 caseAF_InnerBuffer:
2102os <<
"container-specific allocator";
2105os << Family.CustomName.value();
2109assert(
false&&
"not a deallocation expression");
2114 switch(Family.Kind) {
2121 caseAF_CXXNewArray:
2122os <<
"'delete[]'";
2124 caseAF_IfNameIndex:
2125os <<
"'if_freenameindex()'";
2127 caseAF_InnerBuffer:
2128os <<
"container-specific deallocator";
2131os <<
"function that takes ownership of '"<< Family.CustomName.value()
2136assert(
false&&
"not a deallocation expression");
2143 boolHold,
bool&IsKnownToBeAllocated,
2144AllocationFamily Family,
boolReturnsNullOnFailure,
2145std::optional<SVal> ArgValOpt)
const{
2150 SValArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2151 if(!isa<DefinedOrUnknownSVal>(ArgVal))
2156 if(!isa<Loc>(location))
2161std::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))
2191HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2199 if(isa<BlockDataRegion>(R)) {
2200HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2209 if(!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
2215 if(isa<AllocaRegion>(R))
2218HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2231 constRefState *RsBase = State->get<RegionState>(SymBase);
2232 SymbolRefPreviousRetStatusSymbol =
nullptr;
2234IsKnownToBeAllocated =
2235RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2240 if(RsBase->getAllocationFamily().Kind == AF_Alloca) {
2246 if((RsBase->isReleased() || RsBase->isRelinquished()) &&
2248HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2249SymBase, PreviousRetStatusSymbol);
2254}
else if(RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2255RsBase->isEscaped()) {
2258 boolDeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2259 if(!DeallocMatchesAlloc) {
2261RsBase, SymBase, Hold);
2268 if(Offset.isValid() &&
2269!Offset.hasSymbolicOffset() &&
2270Offset.getOffset() != 0) {
2271 const Expr*AllocExpr = cast<Expr>(RsBase->getStmt());
2272HandleOffsetFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2280HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2286State = State->remove<FreeReturnValue>(SymBase);
2290 if(ReturnsNullOnFailure) {
2291 SValRetVal =
C.getSVal(ParentExpr);
2293 if(RetStatusSymbol) {
2294 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2295State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2303assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2308State = State->invalidateRegions({location},
Call.getOriginExpr(),
2309 C.blockCount(),
C.getLocationContext(),
2315 returnState->set<RegionState>(SymBase,
2316RefState::getRelinquished(Family,
2319 returnState->set<RegionState>(SymBase,
2320RefState::getReleased(Family, ParentExpr));
2323std::optional<MallocChecker::CheckKind>
2324MallocChecker::getCheckIfTracked(AllocationFamily Family,
2325 boolIsALeakCheck)
const{
2326 switch(Family.Kind) {
2330 caseAF_IfNameIndex: {
2331 if(ChecksEnabled[CK_MallocChecker])
2332 returnCK_MallocChecker;
2333 returnstd::nullopt;
2336 caseAF_CXXNewArray: {
2338 if(ChecksEnabled[CK_NewDeleteLeaksChecker])
2339 returnCK_NewDeleteLeaksChecker;
2342 if(ChecksEnabled[CK_NewDeleteChecker])
2343 returnCK_NewDeleteChecker;
2345 returnstd::nullopt;
2347 caseAF_InnerBuffer: {
2348 if(ChecksEnabled[CK_InnerPointerChecker])
2349 returnCK_InnerPointerChecker;
2350 returnstd::nullopt;
2353assert(
false&&
"no family");
2354 returnstd::nullopt;
2357assert(
false&&
"unhandled family");
2358 returnstd::nullopt;
2361std::optional<MallocChecker::CheckKind>
2363 boolIsALeakCheck)
const{
2364 if(
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2365 returnCK_MallocChecker;
2367 constRefState *RS =
C.getState()->get<RegionState>(Sym);
2369 returngetCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2372boolMallocChecker::SummarizeValue(raw_ostream &os,
SVal V) {
2373 if(std::optional<nonloc::ConcreteInt> IntVal =
2375os <<
"an integer ("<< IntVal->getValue() <<
")";
2376 else if(std::optional<loc::ConcreteInt> ConstAddr =
2378os <<
"a constant address ("<< ConstAddr->getValue() <<
")";
2380os <<
"the address of the label '"<<
Label->getLabel()->getName() <<
"'";
2387boolMallocChecker::SummarizeRegion(raw_ostream &os,
2390 caseMemRegion::FunctionCodeRegionKind: {
2391 const NamedDecl*FD = cast<FunctionCodeRegion>(MR)->getDecl();
2393os <<
"the address of the function '"<< *FD <<
'\'';
2395os <<
"the address of a function";
2398 caseMemRegion::BlockCodeRegionKind:
2399os <<
"block text";
2401 caseMemRegion::BlockDataRegionKind:
2408 if(isa<StackLocalsSpaceRegion>(MS)) {
2409 const VarRegion*VR = dyn_cast<VarRegion>(MR);
2417os <<
"the address of the local variable '"<< VD->
getName() <<
"'";
2419os <<
"the address of a local stack variable";
2423 if(isa<StackArgumentsSpaceRegion>(MS)) {
2424 const VarRegion*VR = dyn_cast<VarRegion>(MR);
2432os <<
"the address of the parameter '"<< VD->
getName() <<
"'";
2434os <<
"the address of a parameter";
2438 if(isa<GlobalsSpaceRegion>(MS)) {
2439 const VarRegion*VR = dyn_cast<VarRegion>(MR);
2448os <<
"the address of the static variable '"<< VD->
getName() <<
"'";
2450os <<
"the address of the global variable '"<< VD->
getName() <<
"'";
2452os <<
"the address of a global variable";
2463 const Expr*DeallocExpr,
2464AllocationFamily Family)
const{
2466 if(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2471std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2476 if(!BT_BadFree[*CheckKind])
2477BT_BadFree[*CheckKind].reset(
new BugType(
2481llvm::raw_svector_ostream os(buf);
2484 while(
const ElementRegion*ER = dyn_cast_or_null<ElementRegion>(MR))
2485MR = ER->getSuperRegion();
2487os <<
"Argument to ";
2489os <<
"deallocator";
2492 boolSummarized = MR ? SummarizeRegion(os, MR)
2493: SummarizeValue(os, ArgVal);
2495os <<
", which is not memory allocated by ";
2497os <<
"not memory allocated by ";
2501 autoR = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2503R->markInteresting(MR);
2504R->addRange(
Range);
2505 C.emitReport(std::move(R));
2512std::optional<MallocChecker::CheckKind> CheckKind;
2514 if(ChecksEnabled[CK_MallocChecker])
2515CheckKind = CK_MallocChecker;
2516 else if(ChecksEnabled[CK_MismatchedDeallocatorChecker])
2517CheckKind = CK_MismatchedDeallocatorChecker;
2524 if(!BT_FreeAlloca[*CheckKind])
2525BT_FreeAlloca[*CheckKind].reset(
new BugType(
2528 autoR = std::make_unique<PathSensitiveBugReport>(
2529*BT_FreeAlloca[*CheckKind],
2530 "Memory allocated by 'alloca()' should not be deallocated", N);
2532R->addRange(
Range);
2533 C.emitReport(std::move(R));
2539 const Expr*DeallocExpr,
2541 boolOwnershipTransferred)
const{
2543 if(!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2549 if(!BT_MismatchedDealloc)
2550BT_MismatchedDealloc.reset(
2551 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2555llvm::raw_svector_ostream os(buf);
2557 const Expr*AllocExpr = cast<Expr>(RS->getStmt());
2559llvm::raw_svector_ostream AllocOs(AllocBuf);
2561llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2563 if(OwnershipTransferred) {
2565os << DeallocOs.str() <<
" cannot";
2569os <<
" take ownership of memory";
2572os <<
" allocated by "<< AllocOs.str();
2576os <<
" allocated by "<< AllocOs.str();
2578os <<
" should be deallocated by ";
2582os <<
", not "<< DeallocOs.str();
2587 autoR = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2589R->markInteresting(Sym);
2590R->addRange(
Range);
2591R->addVisitor<MallocBugVisitor>(Sym);
2592 C.emitReport(std::move(R));
2598AllocationFamily Family,
2599 const Expr*AllocExpr)
const{
2601 if(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2606std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2614 if(!BT_OffsetFree[*CheckKind])
2615BT_OffsetFree[*CheckKind].reset(
new BugType(
2619llvm::raw_svector_ostream os(buf);
2621llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2624assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2627assert((Offset.isValid() &&
2628!Offset.hasSymbolicOffset() &&
2629Offset.getOffset() != 0) &&
2630 "Only symbols with a valid offset can have offset free errors");
2632 intoffsetBytes = Offset.getOffset() /
C.getASTContext().getCharWidth();
2634os <<
"Argument to ";
2636os <<
"deallocator";
2637os <<
" is offset by " 2640<< ((
abs(offsetBytes) > 1) ?
"bytes":
"byte")
2641<<
" from the start of ";
2643os <<
"memory allocated by "<< AllocNameOs.str();
2645os <<
"allocated memory";
2647 autoR = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2650R->addRange(
Range);
2651 C.emitReport(std::move(R));
2657 if(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2658!ChecksEnabled[CK_InnerPointerChecker]) {
2663std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2668 if(!BT_UseFree[*CheckKind])
2669BT_UseFree[*CheckKind].reset(
new BugType(
2672AllocationFamily AF =
2673 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2675 autoR = std::make_unique<PathSensitiveBugReport>(
2676*BT_UseFree[*CheckKind],
2677AF.Kind == AF_InnerBuffer
2678?
"Inner pointer of container used after re/deallocation" 2679:
"Use of memory after it is freed",
2682R->markInteresting(Sym);
2683R->addRange(
Range);
2684R->addVisitor<MallocBugVisitor>(Sym);
2686 if(AF.Kind == AF_InnerBuffer)
2689 C.emitReport(std::move(R));
2697 if(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2702std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2707 if(!BT_DoubleFree[*CheckKind])
2708BT_DoubleFree[*CheckKind].reset(
new BugType(
2711 autoR = std::make_unique<PathSensitiveBugReport>(
2712*BT_DoubleFree[*CheckKind],
2713(Released ?
"Attempt to free released memory" 2714:
"Attempt to free non-owned memory"),
2716R->addRange(
Range);
2717R->markInteresting(Sym);
2719R->markInteresting(PrevSym);
2720R->addVisitor<MallocBugVisitor>(Sym);
2721 C.emitReport(std::move(R));
2727 if(!ChecksEnabled[CK_NewDeleteChecker]) {
2732std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2737 if(!BT_DoubleDelete)
2738BT_DoubleDelete.reset(
new BugType(CheckNames[CK_NewDeleteChecker],
2742 autoR = std::make_unique<PathSensitiveBugReport>(
2743*BT_DoubleDelete,
"Attempt to delete released memory", N);
2745R->markInteresting(Sym);
2746R->addVisitor<MallocBugVisitor>(Sym);
2747 C.emitReport(std::move(R));
2754 if(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2759std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2765 if(!BT_UseZerroAllocated[*CheckKind])
2766BT_UseZerroAllocated[*CheckKind].reset(
2767 new BugType(CheckNames[*CheckKind],
"Use of zero allocated",
2770 autoR = std::make_unique<PathSensitiveBugReport>(
2771*BT_UseZerroAllocated[*CheckKind],
2772 "Use of memory allocated with size zero", N);
2774R->addRange(
Range);
2776R->markInteresting(Sym);
2777R->addVisitor<MallocBugVisitor>(Sym);
2779 C.emitReport(std::move(R));
2785 const Expr*FreeExpr,
2786AllocationFamily Family)
const{
2787 if(!ChecksEnabled[CK_MallocChecker]) {
2792std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2797 if(!BT_BadFree[*CheckKind])
2798BT_BadFree[*CheckKind].reset(
new BugType(
2802llvm::raw_svector_ostream Os(Buf);
2805 while(
const ElementRegion*ER = dyn_cast_or_null<ElementRegion>(MR))
2806MR = ER->getSuperRegion();
2808Os <<
"Argument to ";
2810Os <<
"deallocator";
2812Os <<
" is a function pointer";
2814 autoR = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2816R->markInteresting(MR);
2817R->addRange(
Range);
2818 C.emitReport(std::move(R));
2825AllocationFamily Family,
boolSuffixWithN)
const{
2829 const CallExpr*CE = cast<CallExpr>(
Call.getOriginExpr());
2837 SValArg0Val =
C.getSVal(arg0Expr);
2838 if(!isa<DefinedOrUnknownSVal>(Arg0Val))
2845State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2851 SValTotalSize =
C.getSVal(Arg1);
2853TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2854 if(!isa<DefinedOrUnknownSVal>(TotalSize))
2860svalBuilder.makeIntValWithWidth(
2861svalBuilder.getContext().getSizeType(), 0));
2864std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2866std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2869 boolPrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2870 boolSizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2874 if(PrtIsNull && !SizeIsZero) {
2881 if(PrtIsNull && SizeIsZero)
2886 boolIsKnownToBeAllocated =
false;
2895 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2900FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2903MallocMemAux(
C,
Call, TotalSize,
UnknownVal(), stateFree, Family);
2907OwnershipAfterReallocKind
Kind= OAR_ToBeFreedAfterFailure;
2908 if(ShouldFreeOnFail)
2909 Kind= OAR_FreeOnFailure;
2910 else if(!IsKnownToBeAllocated)
2911 Kind= OAR_DoNotTrackAfterFailure;
2915 SValRetVal = stateRealloc->getSVal(CE,
C.getLocationContext());
2917assert(FromPtr && ToPtr &&
2918 "By this point, FreeMemAux and MallocMemAux should have checked " 2919 "whether the argument or the return value is symbolic!");
2923stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2924ReallocPair(FromPtr, Kind));
2926 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2927 returnstateRealloc;
2938 if(
Call.getNumArgs() < 2)
2944evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2946 returnMallocMemAux(
C,
Call, TotalSize, zeroVal, State,
2947AllocationFamily(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 SValVal = State->getSVal(MR);
2974ReferenceRegion = MR;
2982 if(NContext == LeakContext ||
2988 returnLeakInfo(AllocNode, ReferenceRegion);
2994 if(!ChecksEnabled[CK_MallocChecker] &&
2995!ChecksEnabled[CK_NewDeleteLeaksChecker])
2998 constRefState *RS =
C.getState()->get<RegionState>(Sym);
2999assert(RS &&
"cannot leak an untracked symbol");
3000AllocationFamily Family = RS->getAllocationFamily();
3002 if(Family.Kind == AF_Alloca)
3005std::optional<MallocChecker::CheckKind> CheckKind =
3006getCheckIfTracked(Family,
true);
3012 if(!BT_Leak[*CheckKind]) {
3018BT_Leak[*CheckKind].reset(
new BugType(CheckNames[*CheckKind],
"Memory leak",
3029std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
3034 C.getSourceManager(),
3038llvm::raw_svector_ostream os(buf);
3040os <<
"Potential leak of memory pointed to by ";
3043os <<
"Potential memory leak";
3046 autoR = std::make_unique<PathSensitiveBugReport>(
3047*BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
3049R->markInteresting(Sym);
3050R->addVisitor<MallocBugVisitor>(Sym,
true);
3051 if(ShouldRegisterNoOwnershipChangeVisitor)
3052R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
3053 C.emitReport(std::move(R));
3056voidMallocChecker::checkDeadSymbols(
SymbolReaper&SymReaper,
3060RegionStateTy OldRS = state->get<RegionState>();
3061RegionStateTy::Factory &F = state->get_context<RegionState>();
3063RegionStateTy RS = OldRS;
3065 for(
auto[Sym, State] : RS) {
3066 if(SymReaper.
isDead(Sym)) {
3067 if(State.isAllocated() || State.isAllocatedOfSizeZero())
3068Errors.push_back(Sym);
3070RS = F.remove(RS, Sym);
3076assert(state->get<ReallocPairs>() ==
3077 C.getState()->get<ReallocPairs>());
3078assert(state->get<FreeReturnValue>() ==
3079 C.getState()->get<FreeReturnValue>());
3084ReallocPairsTy RP = state->get<ReallocPairs>();
3085 for(
auto[Sym, ReallocPair] : RP) {
3086 if(SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
3087state = state->remove<ReallocPairs>(Sym);
3092FreeReturnValueTy FR = state->get<FreeReturnValue>();
3093 for(
auto[Sym, RetSym] : FR) {
3094 if(SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
3095state = state->remove<FreeReturnValue>(Sym);
3101 if(!Errors.empty()) {
3103N =
C.generateNonFatalErrorNode(
C.getState(), &Tag);
3106HandleLeak(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 boolIsKnownToBeAllocated;
3139 false, IsKnownToBeAllocated,
3140AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3142 C.addTransition(State);
3146 if(
const auto*DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3147 SymbolRefSym = 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 SymbolRefSym = CC->getCXXThisVal().getAsSymbol();
3172 if(!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3177 for(
unsignedI = 0,
E=
Call.getNumArgs(); I !=
E; ++I) {
3178 SValArgSVal =
Call.getArgSVal(I);
3179 if(isa<Loc>(ArgSVal)) {
3183 if(checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3189voidMallocChecker::checkPreStmt(
const ReturnStmt*S,
3191checkEscapeOnReturn(S,
C);
3197voidMallocChecker::checkEndFunction(
const ReturnStmt*S,
3199checkEscapeOnReturn(S,
C);
3202voidMallocChecker::checkEscapeOnReturn(
const ReturnStmt*S,
3207 const Expr*
E= S->getRetValue();
3213 SValRetVal =
C.getSVal(
E);
3220 if(isa<FieldRegion, ElementRegion>(MR))
3223Sym = BMR->getSymbol();
3227checkUseAfterFree(Sym,
C,
E);
3233voidMallocChecker::checkPostStmt(
const BlockExpr*BE,
3243cast<BlockDataRegion>(
C.getSVal(BE).getAsRegion());
3246 if(ReferencedVars.empty())
3253 for(
const auto&Var : ReferencedVars) {
3254 const VarRegion*VR = Var.getCapturedRegion();
3258Regions.push_back(VR);
3262state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3263 C.addTransition(state);
3268 constRefState *RS =
C.getState()->get<RegionState>(Sym);
3269 return(RS && RS->isReleased());
3272boolMallocChecker::suppressDeallocationsInSuspiciousContexts(
3274 if(
Call.getNumArgs() == 0)
3277StringRef 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(
SymbolRefSym =
C.getSVal(Arg).getAsSymbol())
3294 if(
constRefState *RS = State->get<RegionState>(Sym))
3295State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3297 C.addTransition(State);
3302 const Stmt*S)
const{
3305HandleUseAfterFree(
C, S->getSourceRange(), Sym);
3313 const Stmt*S)
const{
3316 if(
constRefState *RS =
C.getState()->get<RegionState>(Sym)) {
3317 if(RS->isAllocatedOfSizeZero())
3318HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3320 else if(
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3321HandleUseZeroAlloc(
C, S->getSourceRange(), Sym);
3328HandleDoubleDelete(
C, Sym);
3335voidMallocChecker::checkLocation(
SVall,
boolisLoad,
const Stmt*S,
3339checkUseAfterFree(Sym,
C, S);
3340checkUseZeroAllocated(Sym,
C, S);
3348 boolAssumption)
const{
3349RegionStateTy RS = state->get<RegionState>();
3350 for(
SymbolRefSym : llvm::make_first_range(RS)) {
3355state = state->remove<RegionState>(Sym);
3360ReallocPairsTy RP = state->get<ReallocPairs>();
3361 for(
auto[Sym, ReallocPair] : RP) {
3368 SymbolRefReallocSym = ReallocPair.ReallocatedSym;
3369 if(
constRefState *RS = state->get<RegionState>(ReallocSym)) {
3370 if(RS->isReleased()) {
3371 switch(ReallocPair.Kind) {
3372 caseOAR_ToBeFreedAfterFailure:
3373state = state->set<RegionState>(ReallocSym,
3374RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3376 caseOAR_DoNotTrackAfterFailure:
3377state = state->remove<RegionState>(ReallocSym);
3380assert(ReallocPair.Kind == OAR_FreeOnFailure);
3384state = state->remove<ReallocPairs>(Sym);
3390boolMallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3395EscapingSymbol =
nullptr;
3401 if(!isa<SimpleFunctionCall, ObjCMethodCall>(
Call))
3408 if(!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3421 return*FreeWhenDone;
3427StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3428 if(FirstSlot.ends_with(
"NoCopy"))
3435 if(FirstSlot.starts_with(
"addPointer") ||
3436FirstSlot.starts_with(
"insertPointer") ||
3437FirstSlot.starts_with(
"replacePointer") ||
3438FirstSlot ==
"valueWithPointer") {
3445 if(Msg->getMethodFamily() ==
OMF_init) {
3446EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3462 if(isMemCall(*
Call))
3466 if(!
Call->isInSystemHeader())
3473StringRef FName = II->
getName();
3477 if(FName.ends_with(
"NoCopy")) {
3481 for(
unsignedi = 1; i <
Call->getNumArgs(); ++i) {
3482 const Expr*ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3483 if(
const DeclRefExpr*DE = dyn_cast<DeclRefExpr>(ArgE)) {
3484StringRef 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"||
3504FName ==
"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"||
3520FName ==
"CGBitmapContextCreateWithData"||
3521FName ==
"CVPixelBufferCreateWithBytes"||
3522FName ==
"CVPixelBufferCreateWithPlanarBytes"||
3523FName ==
"OSAtomicEnqueue") {
3527 if(FName ==
"postEvent"&&
3532 if(FName ==
"connectImpl"&&
3537 if(FName ==
"singleShotImpl"&&
3546 if(
Call->argumentsMayEscape())
3558 returncheckPointerEscapeAux(State, Escaped,
Call, Kind,
3567 returncheckPointerEscapeAux(State, Escaped,
Call, Kind,
3572 return(RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3573RS->getAllocationFamily().Kind == AF_CXXNew);
3579 boolIsConstPointerEscape)
const{
3584!mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3591 if(EscapingSymbol && EscapingSymbol != sym)
3594 if(
constRefState *RS = State->get<RegionState>(sym))
3595 if(RS->isAllocated() || RS->isAllocatedOfSizeZero())
3597State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3603 SValArgVal)
const{
3604 if(!KernelZeroSizePtrValue)
3605KernelZeroSizePtrValue =
3608 constllvm::APSInt *ArgValKnown =
3609 C.getSValBuilder().getKnownValue(State, ArgVal);
3610 returnArgValKnown && *KernelZeroSizePtrValue &&
3611ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3616ReallocPairsTy currMap = currState->get<ReallocPairs>();
3617ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3619 for(
constReallocPairsTy::value_type &Pair : prevMap) {
3621 if(!currMap.lookup(sym))
3630StringRef N = II->
getName();
3631 if(N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3632 if(N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3633N.contains_insensitive(
"intrusive") ||
3634N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3648 constRefState *RSCurr = state->get<RegionState>(Sym);
3649 constRefState *RSPrev = statePrev->get<RegionState>(Sym);
3654 if(!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3667 if(ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
3668ReleaseFunctionLC->
isParentOf(CurrentLC))) {
3669 if(
const auto*AE = dyn_cast<AtomicExpr>(S)) {
3672 if(Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3673Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3679}
else if(
const auto*CE = dyn_cast<CallExpr>(S)) {
3682 if(
const auto*MD =
3702std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3704llvm::raw_svector_ostream OS(Buf);
3707 if(isAllocated(RSCurr, RSPrev, S)) {
3708Msg =
"Memory is allocated";
3709StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3710Sym,
"Returned allocated memory");
3711}
else if(
isReleased(RSCurr, RSPrev, S)) {
3712 const autoFamily = RSCurr->getAllocationFamily();
3713 switch(Family.Kind) {
3718 caseAF_CXXNewArray:
3719 caseAF_IfNameIndex:
3720Msg =
"Memory is released";
3721StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3722Sym,
"Returning; memory was released");
3724 caseAF_InnerBuffer: {
3727 const auto*
TypedRegion= cast<TypedValueRegion>(ObjRegion);
3729OS <<
"Inner buffer of '"<< ObjTy <<
"' ";
3732OS <<
"deallocated by call to destructor";
3733StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3734Sym,
"Returning; inner buffer was deallocated");
3736OS <<
"reallocated by call to '";
3737 const Stmt*S = RSCurr->getStmt();
3738 if(
const auto*MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3739OS << MemCallE->getMethodDecl()->getDeclName();
3740}
else if(
const auto*OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3741OS << OpCallE->getDirectCallee()->getDeclName();
3742}
else if(
const auto*CallE = dyn_cast<CallExpr>(S)) {
3745CEMgr.getSimpleCall(CallE, state, CurrentLC, {
nullptr, 0});
3746 if(
const auto*
D= dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
3747OS <<
D->getDeclName();
3752StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3753Sym,
"Returning; inner buffer was reallocated");
3759assert(
false&&
"Unhandled allocation family!");
3764assert(!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)) {
3812Msg =
"Memory ownership is transferred";
3813StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
3814}
else if(hasReallocFailed(RSCurr, RSPrev, S)) {
3815Mode = ReallocationFailed;
3816Msg =
"Reallocation failed";
3817StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3818Sym,
"Reallocation failed");
3822assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3823 "We only support one failed realloc at a time.");
3825FailedReallocSymbol = sym;
3830}
else if(Mode == ReallocationFailed) {
3831assert(FailedReallocSymbol &&
"No symbol to look for.");
3834 if(!statePrev->get<RegionState>(FailedReallocSymbol)) {
3836Msg =
"Attempt to reallocate memory";
3837StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3838Sym,
"Returned reallocated memory");
3839FailedReallocSymbol =
nullptr;
3854assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
3865 auto P= std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
3870voidMallocChecker::printState(raw_ostream &Out,
ProgramStateRefState,
3871 const char*NL,
const char*Sep)
const{
3873RegionStateTy RS = State->get<RegionState>();
3875 if(!RS.isEmpty()) {
3876Out << Sep <<
"MallocChecker :"<< NL;
3877 for(
auto[Sym,
Data] : RS) {
3878 constRefState *RefS = State->get<RegionState>(Sym);
3879AllocationFamily Family = RefS->getAllocationFamily();
3880std::optional<MallocChecker::CheckKind> CheckKind =
3881getCheckIfTracked(Family);
3883CheckKind = getCheckIfTracked(Family,
true);
3889Out <<
" ("<< CheckNames[*CheckKind].getName() <<
")";
3897namespaceallocation_state {
3901AllocationFamily Family(AF_InnerBuffer);
3902 returnState->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3912MallocChecker *checker = mgr.
getChecker<MallocChecker>();
3913checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] =
true;
3914checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3920checker->ShouldIncludeOwnershipAnnotatedFunctions =
3922checker->ShouldRegisterNoOwnershipChangeVisitor =
3924checker,
"AddNoOwnershipChangeNotes");
3927boolento::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::@1704::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.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4