81#include "llvm/ADT/STLExtras.h"
82#include "llvm/ADT/SetOperations.h"
83#include "llvm/ADT/StringExtras.h"
84#include "llvm/Support/Casting.h"
85#include "llvm/Support/Compiler.h"
86#include "llvm/Support/ErrorHandling.h"
87#include "llvm/Support/raw_ostream.h"
94using namespace std::placeholders;
106enum AllocationFamilyKind {
117struct AllocationFamily {
118 AllocationFamilyKind
Kind;
119 std::optional<StringRef> CustomName;
121 explicit AllocationFamily(AllocationFamilyKind AKind,
122 std::optional<StringRef> Name = std::nullopt)
123 :
Kind(AKind), CustomName(Name) {
124 assert((Kind != AF_Custom || CustomName.has_value()) &&
125 "Custom family must specify also the name");
128 if (Kind == AF_Custom && CustomName.value() ==
"malloc") {
130 CustomName = std::nullopt;
135 return std::tie(Kind, CustomName) == std::tie(
Other.Kind,
Other.CustomName);
139 return !(*
this ==
Other);
142 void Profile(llvm::FoldingSetNodeID &ID)
const {
145 if (Kind == AF_Custom)
146 ID.AddString(CustomName.value());
191 AllocationFamily Family;
193 RefState(Kind k,
const Stmt *
s, AllocationFamily family)
194 : S(
s), K(k), Family(family) {
195 assert(family.Kind != AF_None);
199 bool isAllocated()
const {
return K == Allocated; }
200 bool isAllocatedOfSizeZero()
const {
return K == AllocatedOfSizeZero; }
201 bool isReleased()
const {
return K == Released; }
202 bool isRelinquished()
const {
return K == Relinquished; }
203 bool isEscaped()
const {
return K == Escaped; }
204 AllocationFamily getAllocationFamily()
const {
return Family; }
205 const Stmt *getStmt()
const {
return S; }
208 return K ==
X.K && S ==
X.S && Family ==
X.Family;
211 static RefState getAllocated(AllocationFamily family,
const Stmt *
s) {
212 return RefState(Allocated,
s, family);
214 static RefState getAllocatedOfSizeZero(
const RefState *RS) {
215 return RefState(AllocatedOfSizeZero, RS->getStmt(),
216 RS->getAllocationFamily());
218 static RefState getReleased(AllocationFamily family,
const Stmt *
s) {
219 return RefState(Released,
s, family);
221 static RefState getRelinquished(AllocationFamily family,
const Stmt *
s) {
222 return RefState(Relinquished,
s, family);
224 static RefState getEscaped(
const RefState *RS) {
225 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
228 void Profile(llvm::FoldingSetNodeID &ID)
const {
234 LLVM_DUMP_METHOD
void dump(raw_ostream &OS)
const {
236#define CASE(ID) case ID: OS << #ID; break;
238 CASE(AllocatedOfSizeZero)
245 LLVM_DUMP_METHOD
void dump()
const {
dump(llvm::errs()); }
260 AllocationFamily Family,
261 std::optional<SVal> RetVal = std::nullopt);
275enum OwnershipAfterReallocKind {
277 OAR_ToBeFreedAfterFailure,
287 OAR_DoNotTrackAfterFailure
300 OwnershipAfterReallocKind
Kind;
302 ReallocPair(
SymbolRef S, OwnershipAfterReallocKind K)
303 : ReallocatedSym(S),
Kind(K) {}
304 void Profile(llvm::FoldingSetNodeID &ID)
const {
306 ID.AddPointer(ReallocatedSym);
309 return ReallocatedSym ==
X.ReallocatedSym &&
322 if (!
Call.getDecl() || !isa<FunctionDecl>(
Call.getDecl()))
334 :
public Checker<check::DeadSymbols, check::PointerEscape,
335 check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
336 check::EndFunction, check::PreCall, check::PostCall,
337 check::NewAllocator, check::PostStmt<BlockExpr>,
338 check::PostObjCMessage, check::Location, eval::Assume> {
344 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
346 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
356 CK_NewDeleteLeaksChecker,
357 CK_MismatchedDeallocatorChecker,
358 CK_InnerPointerChecker,
359 CK_TaintedAllocChecker,
363 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
365 bool ChecksEnabled[CK_NumCheckKinds] = {
false};
377 bool Assumption)
const;
378 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
391 const char *NL,
const char *Sep)
const override;
394 mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];
395 mutable std::unique_ptr<BugType> BT_DoubleDelete;
396 mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];
397 mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];
398 mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
399 mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
400 mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
401 mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
402 mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
403 mutable std::unique_ptr<BugType> BT_TaintedAlloc;
405#define CHECK_FN(NAME) \
406 void NAME(const CallEvent &Call, CheckerContext &C) const;
427 bool ShouldFreeOnFail)
const;
429 using CheckFn = std::function<void(
const MallocChecker *,
435 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetdelim},
436 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetdelim},
440 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
441 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
442 &MallocChecker::checkIfFreeNameIndex},
443 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
444 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
450 friend class NoMemOwnershipChangeVisitor;
453 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
454 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
458 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
459 &MallocChecker::checkAlloca},
460 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
461 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
462 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
463 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
464 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
465 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
466 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
467 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
468 {{CDM::CLibrary, {
"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
469 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
470 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
471 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
472 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
473 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
474 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
475 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
476 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
477 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
478 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
479 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
483 {{CDM::CLibrary, {
"realloc"}, 2},
484 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
485 {{CDM::CLibrary, {
"reallocf"}, 2},
486 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
true)},
487 {{CDM::CLibrary, {
"g_realloc"}, 2},
488 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
489 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
490 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3,
false)},
491 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
492 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
496 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetdelim},
497 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::checkGetdelim},
503 AllocationFamily Family)
const;
507 AllocationFamily Family)
const;
510 mutable std::optional<uint64_t> KernelZeroFlagVal;
512 using KernelZeroSizePtrValueTy = std::optional<int>;
517 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
523 AllocationFamily Family)
const;
534 ProcessZeroAllocCheck(
const CallEvent &
Call,
const unsigned IndexOfSizeArg,
536 std::optional<SVal> RetVal = std::nullopt);
583 AllocationFamily Family)
const;
587 [[nodiscard]] std::optional<ProgramStateRef>
610 const OwnershipAttr *Att,
634 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
635 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
661 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
662 std::optional<SVal> ArgValOpt = {})
const;
680 bool SuffixWithN =
false)
const;
689 const Expr *BlockBytes);
702 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
711 const Stmt *S)
const;
726 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
735 bool IsConstPointerEscape)
const;
744 std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
745 bool IsALeakCheck =
false)
const;
748 bool IsALeakCheck =
false)
const;
750 static bool SummarizeValue(raw_ostream &os,
SVal V);
751 static bool SummarizeRegion(raw_ostream &os,
const MemRegion *MR);
754 const Expr *DeallocExpr,
755 AllocationFamily Family)
const;
761 const Expr *DeallocExpr,
const RefState *RS,
762 SymbolRef Sym,
bool OwnershipTransferred)
const;
765 const Expr *DeallocExpr, AllocationFamily Family,
766 const Expr *AllocExpr =
nullptr)
const;
780 const Expr *FreeExpr,
781 AllocationFamily Family)
const;
810 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
811 const auto *MallocChk =
static_cast<const MallocChecker *
>(&
Checker);
812 if (MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
813 MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
816 if (
const auto *
Func =
817 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
818 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
825 return CallEnterState->get<RegionState>(Sym) !=
826 CallExitEndState->get<RegionState>(Sym);
833 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
836 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
845 if (
const auto *
Call = Match.getNodeAs<
CallExpr>(
"call"))
846 if (isFreeingCallAsWritten(*
Call))
858 N->getState()->getStateManager().getContext().getSourceManager());
859 return std::make_shared<PathDiagnosticEventPiece>(
860 L,
"Returning without deallocating memory or storing the pointer for "
861 "later deallocation");
868 void Profile(llvm::FoldingSetNodeID &ID)
const override {
887 enum NotificationMode {
Normal, ReallocationFailed };
893 NotificationMode Mode;
905 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
906 : Sym(S), Mode(
Normal), FailedReallocSymbol(nullptr),
907 ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
909 static void *getTag() {
914 void Profile(llvm::FoldingSetNodeID &ID)
const override {
915 ID.AddPointer(getTag());
920 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
922 return (isa_and_nonnull<CallExpr, CXXNewExpr>(
Stmt) &&
924 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
926 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
931 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
934 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
935 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(
Stmt)) ||
936 (!
Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
941 static inline bool isRelinquished(
const RefState *RSCurr,
942 const RefState *RSPrev,
const Stmt *
Stmt) {
944 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(
Stmt) &&
945 (RSCurr && RSCurr->isRelinquished()) &&
946 (!RSPrev || !RSPrev->isRelinquished()));
953 static inline bool hasReallocFailed(
const RefState *RSCurr,
954 const RefState *RSPrev,
956 return ((!isa_and_nonnull<CallExpr>(
Stmt)) &&
958 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
960 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
975 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
980 class StackHintGeneratorForReallocationFailed
983 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
986 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
991 llvm::raw_svector_ostream os(buf);
993 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
994 <<
" parameter failed";
996 return std::string(os.str());
1000 return "Reallocation of returned value failed";
1019 state = state->remove<RegionState>(sym);
1030 if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete &&
1031 Kind != OO_Array_Delete)
1047 if (
Func->hasAttrs()) {
1048 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1049 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1050 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1057bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1058 if (FreeingMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1061 if (
const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl()))
1062 return isFreeingOwnershipAttrCall(
Func);
1068 if (FreeingMemFnMap.lookup(
Call) || AllocatingMemFnMap.lookup(
Call) ||
1069 ReallocatingMemFnMap.lookup(
Call))
1072 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1075 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1076 return Func &&
Func->hasAttr<OwnershipAttr>();
1079std::optional<ProgramStateRef>
1101 if (!KernelZeroFlagVal) {
1103 case llvm::Triple::FreeBSD:
1104 KernelZeroFlagVal = 0x0100;
1106 case llvm::Triple::NetBSD:
1107 KernelZeroFlagVal = 0x0002;
1109 case llvm::Triple::OpenBSD:
1110 KernelZeroFlagVal = 0x0008;
1112 case llvm::Triple::Linux:
1114 KernelZeroFlagVal = 0x8000;
1122 return std::nullopt;
1129 if (
Call.getNumArgs() < 2)
1130 return std::nullopt;
1132 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1133 const SVal V =
C.getSVal(FlagsEx);
1134 if (!isa<NonLoc>(
V)) {
1137 return std::nullopt;
1141 NonLoc ZeroFlag =
C.getSValBuilder()
1142 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1144 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1148 return std::nullopt;
1153 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1156 if (TrueState && !FalseState) {
1157 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1158 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1159 AllocationFamily(AF_Malloc));
1162 return std::nullopt;
1166 const Expr *BlockBytes) {
1168 SVal BlocksVal =
C.getSVal(Blocks);
1169 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1171 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1180 AllocationFamily(AF_Malloc));
1181 State = ProcessZeroAllocCheck(
Call, 0, State);
1182 C.addTransition(State);
1188 std::optional<ProgramStateRef> MaybeState =
1189 performKernelMalloc(
Call,
C, State);
1191 State = *MaybeState;
1194 AllocationFamily(AF_Malloc));
1195 C.addTransition(State);
1221 bool ShouldFreeOnFail)
const {
1231 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1232 AllocationFamily(AF_Malloc));
1233 State = ProcessZeroAllocCheck(
Call, 1, State);
1234 C.addTransition(State);
1240 State = CallocMem(
C,
Call, State);
1241 State = ProcessZeroAllocCheck(
Call, 0, State);
1242 State = ProcessZeroAllocCheck(
Call, 1, State);
1243 C.addTransition(State);
1248 bool IsKnownToBeAllocatedMemory =
false;
1249 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1251 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1252 AllocationFamily(AF_Malloc));
1253 C.addTransition(State);
1260 AllocationFamily(AF_Alloca));
1261 State = ProcessZeroAllocCheck(
Call, 0, State);
1262 C.addTransition(State);
1268 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1273 C.addTransition(State);
1282 AllocationFamily(AF_IfNameIndex));
1284 C.addTransition(State);
1287void MallocChecker::checkIfFreeNameIndex(
const CallEvent &
Call,
1290 bool IsKnownToBeAllocatedMemory =
false;
1291 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1292 AllocationFamily(AF_IfNameIndex));
1293 C.addTransition(State);
1296void MallocChecker::checkCXXNewOrCXXDelete(
const CallEvent &
Call,
1299 bool IsKnownToBeAllocatedMemory =
false;
1300 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1314 AllocationFamily(AF_CXXNew));
1315 State = ProcessZeroAllocCheck(
Call, 0, State);
1319 AllocationFamily(AF_CXXNewArray));
1320 State = ProcessZeroAllocCheck(
Call, 0, State);
1323 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1324 AllocationFamily(AF_CXXNew));
1326 case OO_Array_Delete:
1327 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1328 AllocationFamily(AF_CXXNewArray));
1331 assert(
false &&
"not a new/delete operator");
1335 C.addTransition(State);
1343 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1344 AllocationFamily(AF_Malloc));
1345 State = ProcessZeroAllocCheck(
Call, 0, State);
1346 C.addTransition(State);
1353 AllocationFamily(AF_Malloc));
1354 State = ProcessZeroAllocCheck(
Call, 1, State);
1355 C.addTransition(State);
1362 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1363 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1364 AllocationFamily(AF_Malloc));
1365 State = ProcessZeroAllocCheck(
Call, 0, State);
1366 State = ProcessZeroAllocCheck(
Call, 1, State);
1367 C.addTransition(State);
1375 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1376 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1377 AllocationFamily(AF_Malloc));
1378 State = ProcessZeroAllocCheck(
Call, 0, State);
1379 State = ProcessZeroAllocCheck(
Call, 1, State);
1380 C.addTransition(State);
1385 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1405 bool IsKnownToBeAllocated =
false;
1406 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1407 IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1410 C.addTransition(State);
1423 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1429 const auto LinePtr =
1433 if (!LinePtr || !Size || !LinePtr->getAsRegion())
1438 AllocationFamily(AF_Malloc), *LinePtr));
1444 State = ReallocMemAux(
C,
Call,
false, State,
1445 AllocationFamily(AF_Malloc),
1447 State = ProcessZeroAllocCheck(
Call, 1, State);
1448 State = ProcessZeroAllocCheck(
Call, 2, State);
1449 C.addTransition(State);
1452void MallocChecker::checkOwnershipAttr(
const CallEvent &
Call,
1455 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1461 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1462 ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1467 switch (I->getOwnKind()) {
1468 case OwnershipAttr::Returns:
1469 State = MallocMemReturnsAttr(
C,
Call, I, State);
1471 case OwnershipAttr::Takes:
1472 case OwnershipAttr::Holds:
1473 State = FreeMemAttr(
C,
Call, I, State);
1478 C.addTransition(State);
1485 if (!
Call.getOriginExpr())
1490 if (
const CheckFn *Callback = FreeingMemFnMap.lookup(
Call)) {
1491 (*Callback)(
this,
Call,
C);
1495 if (
const CheckFn *Callback = AllocatingMemFnMap.lookup(
Call)) {
1496 (*Callback)(
this,
Call,
C);
1500 if (
const CheckFn *Callback = ReallocatingMemFnMap.lookup(
Call)) {
1501 (*Callback)(
this,
Call,
C);
1506 checkCXXNewOrCXXDelete(
Call,
C);
1510 checkOwnershipAttr(
Call,
C);
1516 std::optional<SVal> RetVal) {
1521 RetVal =
Call.getReturnValue();
1523 const Expr *Arg =
nullptr;
1525 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1526 Arg = CE->
getArg(IndexOfSizeArg);
1528 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1529 if (
NE->isArray()) {
1530 Arg = *
NE->getArraySize();
1535 assert(
false &&
"not a CallExpr or CXXNewExpr");
1549 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1553 std::tie(TrueState, FalseState) =
1554 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal, Zero));
1556 if (TrueState && !FalseState) {
1557 SymbolRef Sym = RetVal->getAsLocSymbol();
1561 const RefState *RS = State->get<RegionState>(Sym);
1563 if (RS->isAllocated())
1564 return TrueState->set<RegionState>(Sym,
1565 RefState::getAllocatedOfSizeZero(RS));
1573 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1584 while (!PointeeType.isNull()) {
1585 Result = PointeeType;
1586 PointeeType = PointeeType->getPointeeType();
1599 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1605 for (
const auto *CtorParam : CtorD->
parameters()) {
1608 if (CtorParamPointeeT.
isNull())
1623 AllocationFamily Family)
const {
1628 const ParentMap &PM =
C.getLocationContext()->getParentMap();
1643 if (
Call.getOriginExpr()->isArray()) {
1644 if (
auto SizeEx =
NE->getArraySize())
1645 checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1646 AllocationFamily(AF_CXXNewArray));
1650 State = ProcessZeroAllocCheck(
Call, 0, State,
Target);
1656 if (!
C.wasInlined) {
1659 AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1661 C.addTransition(State);
1671 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1672 return FirstSlot ==
"dataWithBytesNoCopy" ||
1673 FirstSlot ==
"initWithBytesNoCopy" ||
1674 FirstSlot ==
"initWithCharactersNoCopy";
1681 for (
unsigned i = 1; i < S.getNumArgs(); ++i)
1682 if (S.getNameForSlot(i) ==
"freeWhenDone")
1683 return !
Call.getArgSVal(i).isZeroConstant();
1685 return std::nullopt;
1700 if (
Call.hasNonZeroCallbackArg())
1703 bool IsKnownToBeAllocatedMemory;
1705 true, IsKnownToBeAllocatedMemory,
1706 AllocationFamily(AF_Malloc),
1709 C.addTransition(State);
1714 const OwnershipAttr *Att,
1719 auto attrClassName = Att->getModule()->getName();
1720 auto Family = AllocationFamily(AF_Custom, attrClassName);
1722 if (!Att->args().empty()) {
1723 return MallocMemAux(
C,
Call,
1724 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1734 AllocationFamily Family)
const {
1739 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
1742void MallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRef State,
1745 AllocationFamily Family)
const {
1746 if (
ExplodedNode *N =
C.generateNonFatalErrorNode(State,
this)) {
1747 if (!BT_TaintedAlloc)
1748 BT_TaintedAlloc.reset(
new BugType(CheckNames[CK_TaintedAllocChecker],
1749 "Tainted Memory Allocation",
1751 auto R = std::make_unique<PathSensitiveBugReport>(*BT_TaintedAlloc, Msg, N);
1752 for (
auto TaintedSym : TaintedSyms) {
1753 R->markInteresting(TaintedSym);
1755 C.emitReport(std::move(R));
1761 AllocationFamily Family)
const {
1762 if (!ChecksEnabled[CK_TaintedAllocChecker])
1764 std::vector<SymbolRef> TaintedSyms =
1766 if (TaintedSyms.empty())
1775 const llvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
1778 std::optional<NonLoc> SizeNL = SizeSVal.
getAs<
NonLoc>();
1779 auto Cmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
1783 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
1784 if (!StateTooLarge && StateNotTooLarge) {
1789 std::string
Callee =
"Memory allocation function";
1790 if (
Call.getCalleeIdentifier())
1791 Callee =
Call.getCalleeIdentifier()->getName().str();
1793 Callee +
" is called with a tainted (potentially attacker controlled) "
1794 "value. Make sure the value is bound checked.",
1795 State,
C, TaintedSyms, Family);
1801 AllocationFamily Family)
const {
1805 const Expr *CE =
Call.getOriginExpr();
1814 unsigned Count =
C.blockCount();
1821 State = State->BindExpr(CE,
C.getLocationContext(), RetVal);
1824 State = State->bindDefaultInitial(RetVal,
Init, LCtx);
1830 checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
1841 AllocationFamily Family,
1842 std::optional<SVal> RetVal) {
1848 RetVal =
C.getSVal(
E);
1851 if (!RetVal->getAs<
Loc>())
1854 SymbolRef Sym = RetVal->getAsLocSymbol();
1869 return State->set<RegionState>(Sym, RefState::getAllocated(Family,
E));
1874 const OwnershipAttr *Att,
1879 auto attrClassName = Att->getModule()->getName();
1880 auto Family = AllocationFamily(AF_Custom, attrClassName);
1882 bool IsKnownToBeAllocated =
false;
1884 for (
const auto &Arg : Att->args()) {
1886 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
1887 Att->getOwnKind() == OwnershipAttr::Holds,
1888 IsKnownToBeAllocated, Family);
1898 bool Hold,
bool &IsKnownToBeAllocated,
1899 AllocationFamily Family,
1900 bool ReturnsNullOnFailure)
const {
1904 if (
Call.getNumArgs() < (Num + 1))
1907 return FreeMemAux(
C,
Call.getArgExpr(Num),
Call, State, Hold,
1908 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
1915 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
1917 assert(*Ret &&
"We should not store the null return symbol");
1920 RetStatusSymbol = *Ret;
1928 const CallExpr *CE = dyn_cast<CallExpr>(
E);
1939 if (I->getOwnKind() != OwnershipAttr::Takes)
1942 os <<
", which takes ownership of '" << I->getModule()->
getName() <<
'\'';
1948 if (
const CallExpr *CE = dyn_cast<CallExpr>(
E)) {
1964 if (Msg->isInstanceMessage())
1968 Msg->getSelector().
print(os);
1972 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(
E)) {
1991 switch (Family.Kind) {
1998 case AF_CXXNewArray:
2001 case AF_IfNameIndex:
2002 os <<
"'if_nameindex()'";
2004 case AF_InnerBuffer:
2005 os <<
"container-specific allocator";
2008 os << Family.CustomName.value();
2012 assert(
false &&
"not a deallocation expression");
2017 switch (Family.Kind) {
2024 case AF_CXXNewArray:
2027 case AF_IfNameIndex:
2028 os <<
"'if_freenameindex()'";
2030 case AF_InnerBuffer:
2031 os <<
"container-specific deallocator";
2034 os <<
"function that takes ownership of '" << Family.CustomName.value()
2039 assert(
false &&
"not a deallocation expression");
2046 bool Hold,
bool &IsKnownToBeAllocated,
2047 AllocationFamily Family,
bool ReturnsNullOnFailure,
2048 std::optional<SVal> ArgValOpt)
const {
2053 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2054 if (!isa<DefinedOrUnknownSVal>(ArgVal))
2059 if (!isa<Loc>(location))
2064 std::tie(notNullState, nullState) = State->assume(location);
2065 if (nullState && !notNullState)
2074 const Expr *ParentExpr =
Call.getOriginExpr();
2093 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2094 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2102 if (isa<BlockDataRegion>(R)) {
2103 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2112 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
2118 if (isa<AllocaRegion>(R))
2121 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2134 const RefState *RsBase = State->get<RegionState>(SymBase);
2135 SymbolRef PreviousRetStatusSymbol =
nullptr;
2137 IsKnownToBeAllocated =
2138 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2143 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2149 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2151 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2152 SymBase, PreviousRetStatusSymbol);
2157 }
else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2158 RsBase->isEscaped()) {
2161 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2162 if (!DeallocMatchesAlloc) {
2164 RsBase, SymBase, Hold);
2171 if (Offset.isValid() &&
2172 !Offset.hasSymbolicOffset() &&
2173 Offset.getOffset() != 0) {
2174 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2183 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2189 State = State->remove<FreeReturnValue>(SymBase);
2193 if (ReturnsNullOnFailure) {
2194 SVal RetVal =
C.getSVal(ParentExpr);
2196 if (RetStatusSymbol) {
2197 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2198 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2206 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2210 return State->set<RegionState>(SymBase,
2211 RefState::getRelinquished(Family,
2214 return State->set<RegionState>(SymBase,
2215 RefState::getReleased(Family, ParentExpr));
2218std::optional<MallocChecker::CheckKind>
2219MallocChecker::getCheckIfTracked(AllocationFamily Family,
2220 bool IsALeakCheck)
const {
2221 switch (Family.Kind) {
2225 case AF_IfNameIndex: {
2226 if (ChecksEnabled[CK_MallocChecker])
2227 return CK_MallocChecker;
2228 return std::nullopt;
2231 case AF_CXXNewArray: {
2233 if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2234 return CK_NewDeleteLeaksChecker;
2237 if (ChecksEnabled[CK_NewDeleteChecker])
2238 return CK_NewDeleteChecker;
2240 return std::nullopt;
2242 case AF_InnerBuffer: {
2243 if (ChecksEnabled[CK_InnerPointerChecker])
2244 return CK_InnerPointerChecker;
2245 return std::nullopt;
2248 assert(
false &&
"no family");
2249 return std::nullopt;
2252 assert(
false &&
"unhandled family");
2253 return std::nullopt;
2256std::optional<MallocChecker::CheckKind>
2258 bool IsALeakCheck)
const {
2259 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2260 return CK_MallocChecker;
2262 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2264 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2267bool MallocChecker::SummarizeValue(raw_ostream &os,
SVal V) {
2268 if (std::optional<nonloc::ConcreteInt> IntVal =
2270 os <<
"an integer (" << IntVal->getValue() <<
")";
2271 else if (std::optional<loc::ConcreteInt> ConstAddr =
2273 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2275 os <<
"the address of the label '" <<
Label->getLabel()->getName() <<
"'";
2282bool MallocChecker::SummarizeRegion(raw_ostream &os,
2285 case MemRegion::FunctionCodeRegionKind: {
2286 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2288 os <<
"the address of the function '" << *FD <<
'\'';
2290 os <<
"the address of a function";
2293 case MemRegion::BlockCodeRegionKind:
2296 case MemRegion::BlockDataRegionKind:
2303 if (isa<StackLocalsSpaceRegion>(MS)) {
2304 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2312 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2314 os <<
"the address of a local stack variable";
2318 if (isa<StackArgumentsSpaceRegion>(MS)) {
2319 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2327 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2329 os <<
"the address of a parameter";
2333 if (isa<GlobalsSpaceRegion>(MS)) {
2334 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2343 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2345 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2347 os <<
"the address of a global variable";
2358 const Expr *DeallocExpr,
2359 AllocationFamily Family)
const {
2361 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2366 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2371 if (!BT_BadFree[*CheckKind])
2372 BT_BadFree[*CheckKind].reset(
new BugType(
2376 llvm::raw_svector_ostream os(buf);
2379 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2380 MR = ER->getSuperRegion();
2382 os <<
"Argument to ";
2384 os <<
"deallocator";
2387 bool Summarized = MR ? SummarizeRegion(os, MR)
2388 : SummarizeValue(os, ArgVal);
2390 os <<
", which is not memory allocated by ";
2392 os <<
"not memory allocated by ";
2396 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2398 R->markInteresting(MR);
2400 C.emitReport(std::move(R));
2407 std::optional<MallocChecker::CheckKind> CheckKind;
2409 if (ChecksEnabled[CK_MallocChecker])
2410 CheckKind = CK_MallocChecker;
2411 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2412 CheckKind = CK_MismatchedDeallocatorChecker;
2419 if (!BT_FreeAlloca[*CheckKind])
2420 BT_FreeAlloca[*CheckKind].reset(
new BugType(
2423 auto R = std::make_unique<PathSensitiveBugReport>(
2424 *BT_FreeAlloca[*CheckKind],
2425 "Memory allocated by 'alloca()' should not be deallocated", N);
2428 C.emitReport(std::move(R));
2434 const Expr *DeallocExpr,
2436 bool OwnershipTransferred)
const {
2438 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2444 if (!BT_MismatchedDealloc)
2445 BT_MismatchedDealloc.reset(
2446 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2450 llvm::raw_svector_ostream os(buf);
2452 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2454 llvm::raw_svector_ostream AllocOs(AllocBuf);
2456 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2458 if (OwnershipTransferred) {
2460 os << DeallocOs.str() <<
" cannot";
2464 os <<
" take ownership of memory";
2467 os <<
" allocated by " << AllocOs.str();
2471 os <<
" allocated by " << AllocOs.str();
2473 os <<
" should be deallocated by ";
2477 os <<
", not " << DeallocOs.str();
2482 auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2484 R->markInteresting(Sym);
2486 R->addVisitor<MallocBugVisitor>(Sym);
2487 C.emitReport(std::move(R));
2493 AllocationFamily Family,
2494 const Expr *AllocExpr)
const {
2496 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2501 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2509 if (!BT_OffsetFree[*CheckKind])
2510 BT_OffsetFree[*CheckKind].reset(
new BugType(
2514 llvm::raw_svector_ostream os(buf);
2516 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2519 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2522 assert((Offset.isValid() &&
2523 !Offset.hasSymbolicOffset() &&
2524 Offset.getOffset() != 0) &&
2525 "Only symbols with a valid offset can have offset free errors");
2527 int offsetBytes = Offset.getOffset() /
C.getASTContext().getCharWidth();
2529 os <<
"Argument to ";
2531 os <<
"deallocator";
2532 os <<
" is offset by "
2535 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2536 <<
" from the start of ";
2538 os <<
"memory allocated by " << AllocNameOs.str();
2540 os <<
"allocated memory";
2542 auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2546 C.emitReport(std::move(R));
2552 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2553 !ChecksEnabled[CK_InnerPointerChecker]) {
2558 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2563 if (!BT_UseFree[*CheckKind])
2564 BT_UseFree[*CheckKind].reset(
new BugType(
2567 AllocationFamily AF =
2568 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2570 auto R = std::make_unique<PathSensitiveBugReport>(
2571 *BT_UseFree[*CheckKind],
2572 AF.Kind == AF_InnerBuffer
2573 ?
"Inner pointer of container used after re/deallocation"
2574 :
"Use of memory after it is freed",
2577 R->markInteresting(Sym);
2579 R->addVisitor<MallocBugVisitor>(Sym);
2581 if (AF.Kind == AF_InnerBuffer)
2584 C.emitReport(std::move(R));
2592 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2597 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2602 if (!BT_DoubleFree[*CheckKind])
2603 BT_DoubleFree[*CheckKind].reset(
new BugType(
2606 auto R = std::make_unique<PathSensitiveBugReport>(
2607 *BT_DoubleFree[*CheckKind],
2608 (Released ?
"Attempt to free released memory"
2609 :
"Attempt to free non-owned memory"),
2612 R->markInteresting(Sym);
2614 R->markInteresting(PrevSym);
2615 R->addVisitor<MallocBugVisitor>(Sym);
2616 C.emitReport(std::move(R));
2622 if (!ChecksEnabled[CK_NewDeleteChecker]) {
2627 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2632 if (!BT_DoubleDelete)
2633 BT_DoubleDelete.reset(
new BugType(CheckNames[CK_NewDeleteChecker],
2637 auto R = std::make_unique<PathSensitiveBugReport>(
2638 *BT_DoubleDelete,
"Attempt to delete released memory", N);
2640 R->markInteresting(Sym);
2641 R->addVisitor<MallocBugVisitor>(Sym);
2642 C.emitReport(std::move(R));
2649 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2654 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(
C, Sym);
2660 if (!BT_UseZerroAllocated[*CheckKind])
2661 BT_UseZerroAllocated[*CheckKind].reset(
2662 new BugType(CheckNames[*CheckKind],
"Use of zero allocated",
2665 auto R = std::make_unique<PathSensitiveBugReport>(
2666 *BT_UseZerroAllocated[*CheckKind],
2667 "Use of memory allocated with size zero", N);
2671 R->markInteresting(Sym);
2672 R->addVisitor<MallocBugVisitor>(Sym);
2674 C.emitReport(std::move(R));
2680 const Expr *FreeExpr,
2681 AllocationFamily Family)
const {
2682 if (!ChecksEnabled[CK_MallocChecker]) {
2687 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2692 if (!BT_BadFree[*CheckKind])
2693 BT_BadFree[*CheckKind].reset(
new BugType(
2697 llvm::raw_svector_ostream Os(Buf);
2700 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2701 MR = ER->getSuperRegion();
2703 Os <<
"Argument to ";
2705 Os <<
"deallocator";
2707 Os <<
" is a function pointer";
2709 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2711 R->markInteresting(MR);
2713 C.emitReport(std::move(R));
2720 AllocationFamily Family,
bool SuffixWithN)
const {
2724 const CallExpr *CE = cast<CallExpr>(
Call.getOriginExpr());
2732 SVal Arg0Val =
C.getSVal(arg0Expr);
2733 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2740 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2746 SVal TotalSize =
C.getSVal(Arg1);
2748 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2749 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2755 svalBuilder.makeIntValWithWidth(
2756 svalBuilder.getContext().getSizeType(), 0));
2759 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2761 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2764 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2765 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2769 if (PrtIsNull && !SizeIsZero) {
2775 if (PrtIsNull && SizeIsZero)
2780 bool IsKnownToBeAllocated =
false;
2789 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2794 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2801 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2802 if (ShouldFreeOnFail)
2803 Kind = OAR_FreeOnFailure;
2804 else if (!IsKnownToBeAllocated)
2805 Kind = OAR_DoNotTrackAfterFailure;
2809 SVal RetVal =
C.getSVal(CE);
2811 assert(FromPtr && ToPtr &&
2812 "By this point, FreeMemAux and MallocMemAux should have checked "
2813 "whether the argument or the return value is symbolic!");
2817 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2818 ReallocPair(FromPtr, Kind));
2820 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2821 return stateRealloc;
2832 if (
Call.getNumArgs() < 2)
2838 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2840 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State,
2841 AllocationFamily(AF_Malloc));
2844MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2851 const MemRegion *ReferenceRegion =
nullptr;
2855 if (!State->get<RegionState>(Sym))
2860 if (!ReferenceRegion) {
2861 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
2862 SVal Val = State->getSVal(MR);
2868 ReferenceRegion = MR;
2876 if (NContext == LeakContext ||
2882 return LeakInfo(AllocNode, ReferenceRegion);
2888 if (!ChecksEnabled[CK_MallocChecker] &&
2889 !ChecksEnabled[CK_NewDeleteLeaksChecker])
2892 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2893 assert(RS &&
"cannot leak an untracked symbol");
2894 AllocationFamily Family = RS->getAllocationFamily();
2896 if (Family.Kind == AF_Alloca)
2899 std::optional<MallocChecker::CheckKind> CheckKind =
2900 getCheckIfTracked(Family,
true);
2906 if (!BT_Leak[*CheckKind]) {
2912 BT_Leak[*CheckKind].reset(
new BugType(CheckNames[*CheckKind],
"Memory leak",
2923 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
2928 C.getSourceManager(),
2932 llvm::raw_svector_ostream os(buf);
2934 os <<
"Potential leak of memory pointed to by ";
2937 os <<
"Potential memory leak";
2940 auto R = std::make_unique<PathSensitiveBugReport>(
2941 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
2943 R->markInteresting(Sym);
2944 R->addVisitor<MallocBugVisitor>(Sym,
true);
2945 if (ShouldRegisterNoOwnershipChangeVisitor)
2946 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
2947 C.emitReport(std::move(R));
2950void MallocChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
2954 RegionStateTy OldRS = state->get<RegionState>();
2955 RegionStateTy::Factory &F = state->get_context<RegionState>();
2957 RegionStateTy RS = OldRS;
2959 for (
auto [Sym, State] : RS) {
2960 if (SymReaper.
isDead(Sym)) {
2961 if (State.isAllocated() || State.isAllocatedOfSizeZero())
2962 Errors.push_back(Sym);
2964 RS = F.remove(RS, Sym);
2970 assert(state->get<ReallocPairs>() ==
2971 C.getState()->get<ReallocPairs>());
2972 assert(state->get<FreeReturnValue>() ==
2973 C.getState()->get<FreeReturnValue>());
2978 ReallocPairsTy RP = state->get<ReallocPairs>();
2979 for (
auto [Sym, ReallocPair] : RP) {
2980 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
2981 state = state->remove<ReallocPairs>(Sym);
2986 FreeReturnValueTy FR = state->get<FreeReturnValue>();
2987 for (
auto [Sym, RetSym] : FR) {
2988 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
2989 state = state->remove<FreeReturnValue>(Sym);
2995 if (!Errors.empty()) {
2997 N =
C.generateNonFatalErrorNode(
C.getState(), &Tag);
3000 HandleLeak(Sym, N,
C);
3005 C.addTransition(state->set<RegionState>(RS), N);
3011 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3014 if (!ChecksEnabled[CK_NewDeleteChecker])
3022 bool IsKnownToBeAllocated;
3025 false, IsKnownToBeAllocated,
3026 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3028 C.addTransition(State);
3032 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3033 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3034 if (!Sym || checkDoubleDelete(Sym,
C))
3040 if (
const auto *PreFN = PreFnMap.lookup(
Call)) {
3041 (*PreFN)(
this,
Call,
C);
3051 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(
Call))
3057 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3058 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3063 for (
unsigned I = 0,
E =
Call.getNumArgs(); I !=
E; ++I) {
3065 if (isa<Loc>(ArgSVal)) {
3069 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3075void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3077 checkEscapeOnReturn(S,
C);
3083void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3085 checkEscapeOnReturn(S,
C);
3088void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3093 const Expr *
E = S->getRetValue();
3099 SVal RetVal =
C.getSVal(
E);
3106 if (isa<FieldRegion, ElementRegion>(MR))
3109 Sym = BMR->getSymbol();
3113 checkUseAfterFree(Sym,
C,
E);
3119void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3129 cast<BlockDataRegion>(
C.getSVal(BE).getAsRegion());
3132 if (ReferencedVars.empty())
3139 for (
const auto &Var : ReferencedVars) {
3140 const VarRegion *VR = Var.getCapturedRegion();
3144 Regions.push_back(VR);
3148 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3149 C.addTransition(state);
3154 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3155 return (RS && RS->isReleased());
3158bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3160 if (
Call.getNumArgs() == 0)
3163 StringRef FunctionStr =
"";
3164 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3166 if (Body->getBeginLoc().isValid())
3170 C.getSourceManager(),
C.getLangOpts());
3173 if (!FunctionStr.contains(
"__isl_"))
3178 for (
const Expr *Arg : cast<CallExpr>(
Call.getOriginExpr())->arguments())
3179 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3180 if (
const RefState *RS = State->get<RegionState>(Sym))
3181 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3183 C.addTransition(State);
3188 const Stmt *S)
const {
3191 HandleUseAfterFree(
C, S->getSourceRange(), Sym);
3199 const Stmt *S)
const {
3202 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3203 if (RS->isAllocatedOfSizeZero())
3204 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3206 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3207 HandleUseZeroAlloc(
C, S->getSourceRange(), Sym);
3214 HandleDoubleDelete(
C, Sym);
3221void MallocChecker::checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
3225 checkUseAfterFree(Sym,
C, S);
3226 checkUseZeroAllocated(Sym,
C, S);
3234 bool Assumption)
const {
3235 RegionStateTy RS = state->get<RegionState>();
3236 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3241 state = state->remove<RegionState>(Sym);
3246 ReallocPairsTy RP = state->get<ReallocPairs>();
3247 for (
auto [Sym, ReallocPair] : RP) {
3254 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3255 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3256 if (RS->isReleased()) {
3257 switch (ReallocPair.Kind) {
3258 case OAR_ToBeFreedAfterFailure:
3259 state = state->set<RegionState>(ReallocSym,
3260 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3262 case OAR_DoNotTrackAfterFailure:
3263 state = state->remove<RegionState>(ReallocSym);
3266 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3270 state = state->remove<ReallocPairs>(Sym);
3276bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3281 EscapingSymbol =
nullptr;
3287 if (!isa<SimpleFunctionCall, ObjCMethodCall>(
Call))
3294 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3307 return *FreeWhenDone;
3313 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3314 if (FirstSlot.ends_with(
"NoCopy"))
3321 if (FirstSlot.starts_with(
"addPointer") ||
3322 FirstSlot.starts_with(
"insertPointer") ||
3323 FirstSlot.starts_with(
"replacePointer") ||
3324 FirstSlot ==
"valueWithPointer") {
3331 if (Msg->getMethodFamily() ==
OMF_init) {
3332 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3348 if (isMemCall(*
Call))
3352 if (!
Call->isInSystemHeader())
3359 StringRef FName = II->
getName();
3363 if (FName.ends_with(
"NoCopy")) {
3367 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3368 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3369 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3370 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3371 if (DeallocatorName ==
"kCFAllocatorNull")
3382 if (FName ==
"funopen")
3383 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3389 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3390 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3391 if (
Call->getNumArgs() >= 1) {
3392 const Expr *ArgE =
Call->getArgExpr(0)->IgnoreParenCasts();
3393 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3394 if (
const VarDecl *
D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3405 if (FName ==
"CGBitmapContextCreate" ||
3406 FName ==
"CGBitmapContextCreateWithData" ||
3407 FName ==
"CVPixelBufferCreateWithBytes" ||
3408 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3409 FName ==
"OSAtomicEnqueue") {
3413 if (FName ==
"postEvent" &&
3418 if (FName ==
"connectImpl" &&
3423 if (FName ==
"singleShotImpl" &&
3432 if (
Call->argumentsMayEscape())
3444 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3453 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3458 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3459 RS->getAllocationFamily().Kind == AF_CXXNew);
3465 bool IsConstPointerEscape)
const {
3470 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3477 if (EscapingSymbol && EscapingSymbol != sym)
3480 if (
const RefState *RS = State->get<RegionState>(sym))
3481 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3483 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3489 SVal ArgVal)
const {
3490 if (!KernelZeroSizePtrValue)
3491 KernelZeroSizePtrValue =
3494 const llvm::APSInt *ArgValKnown =
3495 C.getSValBuilder().getKnownValue(State, ArgVal);
3496 return ArgValKnown && *KernelZeroSizePtrValue &&
3497 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3502 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3503 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3505 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3507 if (!currMap.lookup(sym))
3517 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3518 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3519 N.contains_insensitive(
"intrusive") ||
3520 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3534 const RefState *RSCurr = state->get<RegionState>(Sym);
3535 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3540 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3552 if (ReleaseDestructorLC && (ReleaseDestructorLC == CurrentLC ||
3553 ReleaseDestructorLC->
isParentOf(CurrentLC))) {
3554 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3557 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3558 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3561 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
3564 if (
const auto *MD =
3581 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3583 llvm::raw_svector_ostream OS(Buf);
3586 if (isAllocated(RSCurr, RSPrev, S)) {
3587 Msg =
"Memory is allocated";
3588 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3589 Sym,
"Returned allocated memory");
3591 const auto Family = RSCurr->getAllocationFamily();
3592 switch (Family.Kind) {
3597 case AF_CXXNewArray:
3598 case AF_IfNameIndex:
3599 Msg =
"Memory is released";
3600 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3601 Sym,
"Returning; memory was released");
3603 case AF_InnerBuffer: {
3606 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
3608 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
3611 OS <<
"deallocated by call to destructor";
3612 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3613 Sym,
"Returning; inner buffer was deallocated");
3615 OS <<
"reallocated by call to '";
3616 const Stmt *S = RSCurr->getStmt();
3617 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3618 OS << MemCallE->getMethodDecl()->getDeclName();
3619 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3620 OS << OpCallE->getDirectCallee()->getDeclName();
3621 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
3624 CEMgr.getSimpleCall(CallE, state, CurrentLC, {
nullptr, 0});
3625 if (
const auto *
D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
3626 OS <<
D->getDeclName();
3631 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3632 Sym,
"Returning; inner buffer was reallocated");
3638 assert(
false &&
"Unhandled allocation family!");
3645 bool FoundAnyDestructor =
false;
3647 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
3653 }
else if (!FoundAnyDestructor) {
3654 assert(!ReleaseDestructorLC &&
3655 "There can be only one release point!");
3667 FoundAnyDestructor =
true;
3671 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
3672 Msg =
"Memory ownership is transferred";
3673 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
3674 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3675 Mode = ReallocationFailed;
3676 Msg =
"Reallocation failed";
3677 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3678 Sym,
"Reallocation failed");
3682 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3683 "We only support one failed realloc at a time.");
3685 FailedReallocSymbol = sym;
3690 }
else if (Mode == ReallocationFailed) {
3691 assert(FailedReallocSymbol &&
"No symbol to look for.");
3694 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3696 Msg =
"Attempt to reallocate memory";
3697 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3698 Sym,
"Returned reallocated memory");
3699 FailedReallocSymbol =
nullptr;
3714 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
3725 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
3730void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
3731 const char *NL,
const char *Sep)
const {
3733 RegionStateTy RS = State->get<RegionState>();
3735 if (!RS.isEmpty()) {
3736 Out << Sep <<
"MallocChecker :" << NL;
3737 for (
auto [Sym,
Data] : RS) {
3738 const RefState *RefS = State->get<RegionState>(Sym);
3739 AllocationFamily Family = RefS->getAllocationFamily();
3740 std::optional<MallocChecker::CheckKind> CheckKind =
3741 getCheckIfTracked(Family);
3743 CheckKind = getCheckIfTracked(Family,
true);
3749 Out <<
" (" << CheckNames[*CheckKind].getName() <<
")";
3757namespace allocation_state {
3761 AllocationFamily Family(AF_InnerBuffer);
3762 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3772 MallocChecker *checker = mgr.
getChecker<MallocChecker>();
3773 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] =
true;
3774 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3780 checker->ShouldIncludeOwnershipAnnotatedFunctions =
3782 checker->ShouldRegisterNoOwnershipChangeVisitor =
3784 checker,
"AddNoOwnershipChangeNotes");
3787bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
3791#define REGISTER_CHECKER(name) \
3792 void ento::register##name(CheckerManager &mgr) { \
3793 MallocChecker *checker = mgr.getChecker<MallocChecker>(); \
3794 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
3795 checker->CheckNames[MallocChecker::CK_##name] = \
3796 mgr.getCurrentCheckerName(); \
3799 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
enum clang::sema::@1651::IndirectLocalPathEntry::EntryKind Kind
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::Target Target
static bool isFromStdNamespace(const CallEvent &Call)
#define REGISTER_CHECKER(name)
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
static QualType getDeepPointeeType(QualType T)
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)
Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
static bool isGRealloc(const CallEvent &Call)
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)
Print expected name of a deallocator based on the allocator's family.
static bool isStandardRealloc(const CallEvent &Call)
static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)
Checks if the previous call to free on the given symbol failed - if free failed, returns true.
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)
Update the RefState to reflect the new memory allocation.
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool isStandardNewDelete(const FunctionDecl *FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
static bool contains(const std::set< tok::TokenKind > &Terminators, const Token &Tok)
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
__device__ __2f16 float __ockl_bool s
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Represents a C++ constructor within a class.
Represents a delete expression for memory deallocation and destructor calls, e.g.
Represents a C++ destructor within a class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Represents a C++ struct/union/class.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
static CharSourceRange getTokenRange(SourceRange R)
DeclContext * getParent()
getParent - Returns the containing DeclContext.
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
ASTContext & getASTContext() const LLVM_READONLY
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
SourceLocation getLocation() const
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
ArrayRef< ParmVarDecl * > parameters() const
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
QualType getDeclaredReturnType() const
Get the declared return type, which may differ from the actual return type if the return type is dedu...
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
This represents a decl that may have a name.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
An expression that sends a message to the given Objective-C object or class.
bool isConsumedExpr(Expr *E) const
Represents a program point just after an implicit call event.
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Smart pointer class that efficiently represents Objective-C method names.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
A trivial tuple used to represent a source range.
It represents a stack frame of the call stack (based on CallEvent).
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isFunctionPointerType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Maps string IDs to AST nodes matched by parts of a matcher.
A record of the "type" of an APSInt, used for conversions.
Represents a call to any sort of function that might have a FunctionDecl.
const llvm::APSInt & getMaxValue(const llvm::APSInt &v)
BlockDataRegion - A region that represents a block instance.
llvm::iterator_range< referenced_vars_iterator > referenced_vars() const
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
ProgramStateManager & getStateManager() const
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
virtual void Profile(llvm::FoldingSetNodeID &ID) const =0
virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR)=0
Return a diagnostic piece which should be associated with the given node.
virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR)
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
Represents the memory allocation call in a C++ new-expression.
Represents a non-static C++ member function call, no matter how it is written.
An immutable map from CallDescriptions to arbitrary data.
Represents an abstract call to a function or method along a particular path.
virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const
See CheckerManager::runCheckersForPrintState.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
CheckerNameRef getCurrentCheckerName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
ElementRegion is used to represent both array elements and casts.
const ProgramStateRef & getState() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
static bool isLocType(QualType T)
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
Represents any expression that calls an Objective-C method.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
void addCallStackHint(PathDiagnosticPieceRef Piece, std::unique_ptr< StackHintGenerator > StackHint)
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
CallEventManager & getCallEventManager()
A Range represents the closed range [from, to].
Represent a region's offset within the top level base region.
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...
DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Conjure a symbol representing heap allocated memory region.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isUnknownOrUndef() const
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
const MemRegion * getAsRegion() const
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Constructs a Stack hint for the given symbol.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
virtual void dumpToStream(raw_ostream &os) const
virtual QualType getType() const =0
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
virtual bool VisitSymbol(SymbolRef sym)=0
A visitor method invoked by ProgramStateManager::scanReachableSymbols.
SymbolicRegion - A special, "non-concrete" region.
SymbolRef getSymbol() const
It might return null.
TypedRegion - An abstract class representing regions that are typed.
const VarDecl * getDecl() const override=0
const StackFrameContext * getStackFrame() const
It might return null.
Value representing integer constant.
Defines the clang::TargetInfo interface.
__inline void unsigned int _2
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDeleteExpr > cxxDeleteExpr
Matches delete expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)
This function provides an additional visitor that augments the bug report with information relevant t...
const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)
'Sym' represents a pointer to the inner buffer of a container object.
const char *const MemoryError
const char *const TaintedData
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given Statement and state.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
std::optional< SVal > getPointeeVal(SVal PtrSVal, ProgramStateRef State)
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent, SValBuilder &SVB)
Set the dynamic extent Extent of the region MR.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool NE(InterpState &S, CodePtr OpPC)
bool Zero(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
bool operator!=(CanQual< T > x, CanQual< U > y)
const FunctionProtoType * T
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.
@ Other
Other implicit parameter.