80#include "llvm/ADT/STLExtras.h"
81#include "llvm/ADT/SmallVector.h"
82#include "llvm/ADT/StringExtras.h"
83#include "llvm/Support/Casting.h"
84#include "llvm/Support/Compiler.h"
85#include "llvm/Support/ErrorHandling.h"
86#include "llvm/Support/raw_ostream.h"
93using namespace std::placeholders;
105enum AllocationFamilyKind {
116struct AllocationFamily {
117 AllocationFamilyKind Kind;
118 std::optional<StringRef> CustomName;
120 explicit AllocationFamily(AllocationFamilyKind AKind,
121 std::optional<StringRef> Name = std::nullopt)
122 : Kind(AKind), CustomName(Name) {
123 assert((Kind != AF_Custom || CustomName.has_value()) &&
124 "Custom family must specify also the name");
127 if (Kind == AF_Custom && CustomName.value() ==
"malloc") {
129 CustomName = std::nullopt;
134 return std::tie(Kind, CustomName) == std::tie(
Other.Kind,
Other.CustomName);
138 return !(*
this ==
Other);
141 void Profile(llvm::FoldingSetNodeID &ID)
const {
144 if (Kind == AF_Custom)
145 ID.AddString(CustomName.value());
190 AllocationFamily Family;
192 RefState(Kind k,
const Stmt *
s, AllocationFamily family)
193 : S(
s), K(k), Family(family) {
194 assert(family.Kind != AF_None);
198 bool isAllocated()
const {
return K == Allocated; }
199 bool isAllocatedOfSizeZero()
const {
return K == AllocatedOfSizeZero; }
200 bool isReleased()
const {
return K == Released; }
201 bool isRelinquished()
const {
return K == Relinquished; }
202 bool isEscaped()
const {
return K == Escaped; }
203 AllocationFamily getAllocationFamily()
const {
return Family; }
204 const Stmt *getStmt()
const {
return S; }
207 return K ==
X.K && S ==
X.S && Family ==
X.Family;
210 static RefState getAllocated(AllocationFamily family,
const Stmt *
s) {
211 return RefState(Allocated,
s, family);
213 static RefState getAllocatedOfSizeZero(
const RefState *RS) {
214 return RefState(AllocatedOfSizeZero, RS->getStmt(),
215 RS->getAllocationFamily());
217 static RefState getReleased(AllocationFamily family,
const Stmt *
s) {
218 return RefState(Released,
s, family);
220 static RefState getRelinquished(AllocationFamily family,
const Stmt *
s) {
221 return RefState(Relinquished,
s, family);
223 static RefState getEscaped(
const RefState *RS) {
224 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
227 void Profile(llvm::FoldingSetNodeID &ID)
const {
233 LLVM_DUMP_METHOD
void dump(raw_ostream &
OS)
const {
235#define CASE(ID) case ID: OS << #ID; break;
237 CASE(AllocatedOfSizeZero)
244 LLVM_DUMP_METHOD
void dump()
const {
dump(llvm::errs()); }
259 AllocationFamily Family,
260 std::optional<SVal> RetVal = std::nullopt);
274enum OwnershipAfterReallocKind {
276 OAR_ToBeFreedAfterFailure,
286 OAR_DoNotTrackAfterFailure
299 OwnershipAfterReallocKind Kind;
301 ReallocPair(
SymbolRef S, OwnershipAfterReallocKind K)
302 : ReallocatedSym(S), Kind(K) {}
303 void Profile(llvm::FoldingSetNodeID &ID)
const {
305 ID.AddPointer(ReallocatedSym);
308 return ReallocatedSym ==
X.ReallocatedSym &&
344#define BUGTYPE_PROVIDER(NAME, DEF) \
345 struct NAME : virtual public CheckerFrontend { \
346 BugType NAME##Bug{this, DEF, categories::MemoryError}; \
368#undef BUGTYPE_PROVIDER
370template <
typename... BT_PROVIDERS>
371struct DynMemFrontend :
virtual public CheckerFrontend,
public BT_PROVIDERS... {
372 template <
typename T>
const T *getAs()
const {
373 if constexpr (std::is_same_v<T, CheckerFrontend> ||
374 (std::is_same_v<T, BT_PROVIDERS> || ...))
375 return static_cast<const T *
>(
this);
386 check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape,
387 check::PreStmt<ReturnStmt>, check::EndFunction, check::PreCall,
388 check::PostCall, eval::Call, check::NewAllocator,
389 check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location,
396 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
398 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
407 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
410 DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
412 DynMemFrontend<Leak> NewDeleteLeaksChecker;
413 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
414 DynMemFrontend<UseFree> InnerPointerChecker;
417 CheckerFrontendWithBugType TaintedAllocChecker{
"Tainted Memory Allocation",
420 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
422 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
423 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
424 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
427 handleSmartPointerConstructorArguments(
const CallEvent &
Call,
432 void checkNewAllocator(
const CXXAllocatorCall &
Call, CheckerContext &
C)
const;
433 void checkPostObjCMessage(
const ObjCMethodCall &
Call, CheckerContext &
C)
const;
434 void checkPostStmt(
const BlockExpr *BE, CheckerContext &
C)
const;
435 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &
C)
const;
436 void checkPreStmt(
const ReturnStmt *S, CheckerContext &
C)
const;
437 void checkEndFunction(
const ReturnStmt *S, CheckerContext &
C)
const;
439 bool Assumption)
const;
440 void checkLocation(SVal l,
bool isLoad,
const Stmt *S,
441 CheckerContext &
C)
const;
445 const CallEvent *
Call,
449 const CallEvent *
Call,
453 const char *NL,
const char *Sep)
const override;
455 StringRef getDebugTag()
const override {
return "MallocChecker"; }
458#define CHECK_FN(NAME) \
459 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
490 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},
491 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},
494 const CallDescriptionMap<CheckFn> PostFnMap{
497 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},
498 {{CDM::CLibrary, {
"getdelim"}, 4},
499 &MallocChecker::checkGetDelimOrGetLine},
502 const CallDescriptionMap<CheckFn> FreeingMemFnMap{
503 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
504 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
505 &MallocChecker::checkIfFreeNameIndex},
506 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
507 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
510 bool isFreeingCall(
const CallEvent &
Call)
const;
511 static bool isFreeingOwnershipAttrCall(
const FunctionDecl *
Func);
512 static bool isFreeingOwnershipAttrCall(
const CallEvent &
Call);
513 static bool isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func);
514 static bool isAllocatingOwnershipAttrCall(
const CallEvent &
Call);
516 friend class NoMemOwnershipChangeVisitor;
518 CallDescriptionMap<CheckFn> AllocaMemFnMap{
519 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
520 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
524 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
525 &MallocChecker::checkAlloca},
528 CallDescriptionMap<CheckFn> AllocatingMemFnMap{
529 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
530 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
531 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
532 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
533 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
534 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
535 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
536 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
537 {{CDM::CLibrary, {
"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
538 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
539 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
540 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
541 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
542 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
543 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
544 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
545 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
546 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
547 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
548 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
551 CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
552 {{CDM::CLibrary, {
"realloc"}, 2},
553 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
554 {{CDM::CLibrary, {
"reallocf"}, 2},
555 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
true)},
556 {{CDM::CLibrary, {
"g_realloc"}, 2},
557 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
558 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
559 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
560 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
561 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
564 bool isMemCall(
const CallEvent &
Call)
const;
565 bool hasOwnershipReturns(
const CallEvent &
Call)
const;
566 bool hasOwnershipTakesHolds(
const CallEvent &
Call)
const;
567 void reportTaintBug(StringRef Msg,
ProgramStateRef State, CheckerContext &
C,
568 llvm::ArrayRef<SymbolRef> TaintedSyms,
569 AllocationFamily Family)
const;
571 void checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
573 AllocationFamily Family)
const;
576 mutable std::optional<uint64_t> KernelZeroFlagVal;
578 using KernelZeroSizePtrValueTy = std::optional<int>;
583 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
588 processNewAllocation(
const CXXAllocatorCall &
Call, CheckerContext &
C,
589 AllocationFamily Family)
const;
600 ProcessZeroAllocCheck(CheckerContext &
C,
const CallEvent &
Call,
602 std::optional<SVal> RetVal = std::nullopt);
621 MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
631 const CallEvent &
Call,
633 bool isAlloca)
const;
645 MallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
const Expr *SizeEx,
658 const CallEvent &
Call, SVal Size,
660 AllocationFamily Family)
const;
664 [[nodiscard]] std::optional<ProgramStateRef>
665 performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
686 const CallEvent &
Call,
687 const OwnershipAttr *Att,
711 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
712 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
736 FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
const CallEvent &
Call,
738 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
739 std::optional<SVal> ArgValOpt = {})
const;
755 ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
bool ShouldFreeOnFail,
757 bool SuffixWithN =
false)
const;
764 [[nodiscard]]
static SVal evalMulForBufferSize(CheckerContext &
C,
766 const Expr *BlockBytes);
774 const CallEvent &
Call,
779 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
780 CheckerContext &
C)
const;
783 bool checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
const Stmt *S)
const;
787 void checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
788 const Stmt *S)
const;
800 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
809 bool IsConstPointerEscape)
const;
812 void checkEscapeOnReturn(
const ReturnStmt *S, CheckerContext &
C)
const;
821 const T *getRelevantFrontendAs(AllocationFamily Family)
const;
824 const T *getRelevantFrontendAs(CheckerContext &
C,
SymbolRef Sym)
const;
826 static bool SummarizeValue(raw_ostream &os, SVal
V);
828 const MemRegion *MR);
830 void HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal, SourceRange Range,
831 const Expr *DeallocExpr,
832 AllocationFamily Family)
const;
834 void HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
835 SourceRange Range)
const;
837 void HandleMismatchedDealloc(CheckerContext &
C, SourceRange Range,
838 const Expr *DeallocExpr,
const RefState *RS,
839 SymbolRef Sym,
bool OwnershipTransferred)
const;
841 void HandleOffsetFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
842 const Expr *DeallocExpr, AllocationFamily Family,
843 const Expr *AllocExpr =
nullptr)
const;
845 void HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
848 void HandleDoubleFree(CheckerContext &
C, SourceRange Range,
bool Released,
851 void HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
854 void HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
855 const Expr *FreeExpr,
856 AllocationFamily Family)
const;
860 static LeakInfo getAllocationSite(
const ExplodedNode *N,
SymbolRef Sym,
863 void HandleLeak(
SymbolRef Sym, ExplodedNode *N, CheckerContext &
C)
const;
876class NoMemOwnershipChangeVisitor final :
public NoOwnershipChangeVisitor {
885 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
886 const auto *MallocChk =
static_cast<const MallocChecker *
>(&Checker);
887 if (MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
888 MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
891 if (
const auto *
Func =
892 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
893 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
900 return CallEnterState->get<RegionState>(Sym) !=
901 CallExitEndState->get<RegionState>(Sym);
908 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
909 ASTContext &ACtx)
final {
910 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
920 using namespace clang::ast_matchers;
925 for (BoundNodes
Match : Matches) {
926 if (
Match.getNodeAs<CXXDeleteExpr>(
"delete"))
929 if (
const auto *
Call =
Match.getNodeAs<CallExpr>(
"call"))
930 if (isFreeingCallAsWritten(*
Call))
942 N->getState()->getStateManager().getContext().getSourceManager());
943 return std::make_shared<PathDiagnosticEventPiece>(
944 L,
"Returning without deallocating memory or storing the pointer for "
945 "later deallocation");
949 NoMemOwnershipChangeVisitor(
SymbolRef Sym,
const MallocChecker *Checker)
950 : NoOwnershipChangeVisitor(Sym, Checker) {}
952 void Profile(llvm::FoldingSetNodeID &ID)
const override {
971 enum NotificationMode { Normal, ReallocationFailed };
977 NotificationMode Mode;
984 const StackFrameContext *ReleaseFunctionLC;
989 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
990 : Sym(S), Mode(Normal), FailedReallocSymbol(
nullptr),
991 ReleaseFunctionLC(
nullptr), IsLeak(isLeak) {}
993 static void *getTag() {
998 void Profile(llvm::FoldingSetNodeID &ID)
const override {
999 ID.AddPointer(getTag());
1004 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
1006 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
1008 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1010 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1015 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
1018 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
1019 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
1020 (!Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
1025 static inline bool isRelinquished(
const RefState *RSCurr,
1026 const RefState *RSPrev,
const Stmt *Stmt) {
1028 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
1029 (RSCurr && RSCurr->isRelinquished()) &&
1030 (!RSPrev || !RSPrev->isRelinquished()));
1037 static inline bool hasReallocFailed(
const RefState *RSCurr,
1038 const RefState *RSPrev,
1040 return ((!isa_and_nonnull<CallExpr>(Stmt)) &&
1042 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1044 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1048 BugReporterContext &BRC,
1049 PathSensitiveBugReport &BR)
override;
1052 const ExplodedNode *EndPathNode,
1053 PathSensitiveBugReport &BR)
override {
1059 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1064 class StackHintGeneratorForReallocationFailed
1065 :
public StackHintGeneratorForSymbol {
1067 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1068 : StackHintGeneratorForSymbol(S, M) {}
1070 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1074 SmallString<200> buf;
1075 llvm::raw_svector_ostream os(buf);
1077 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1078 <<
" parameter failed";
1080 return std::string(os.str());
1083 std::string getMessageForReturn(
const CallExpr *CallExpr)
override {
1084 return "Reallocation of returned value failed";
1102 bool VisitSymbol(
SymbolRef sym)
override {
1103 state = state->remove<RegionState>(sym);
1123 explicit EscapeTrackedCallback(
ProgramStateRef S) : State(std::move(S)) {}
1126 bool VisitSymbol(
SymbolRef Sym)
override {
1127 if (
const RefState *RS = State->get<RegionState>(Sym)) {
1128 if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) {
1129 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
1137 EscapeTrackedRegionsReachableFrom(ArrayRef<const MemRegion *> Roots,
1144 SmallVector<const MemRegion *, 10> Regions;
1145 EscapeTrackedCallback Visitor(State);
1146 for (
const MemRegion *R : Roots) {
1147 Regions.push_back(R);
1149 State->scanReachableSymbols(Regions, Visitor);
1150 return Visitor.State;
1153 friend class SymbolVisitor;
1162 if (Kind != OO_New && Kind != OO_Array_New)
1178 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1189 return L.
isInvalid() || (!HasBody &&
SM.isInSystemHeader(L));
1196bool MallocChecker::isFreeingOwnershipAttrCall(
const CallEvent &
Call) {
1197 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1199 return Func && isFreeingOwnershipAttrCall(
Func);
1202bool MallocChecker::isFreeingOwnershipAttrCall(
const FunctionDecl *
Func) {
1203 if (
Func->hasAttrs()) {
1204 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1205 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1206 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1213bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1214 if (FreeingMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1217 return isFreeingOwnershipAttrCall(
Call);
1220bool MallocChecker::isAllocatingOwnershipAttrCall(
const CallEvent &
Call) {
1221 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1223 return Func && isAllocatingOwnershipAttrCall(
Func);
1226bool MallocChecker::isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func) {
1227 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1228 if (I->getOwnKind() == OwnershipAttr::Returns)
1235bool MallocChecker::isMemCall(
const CallEvent &
Call)
const {
1236 if (FreeingMemFnMap.lookup(
Call) || AllocatingMemFnMap.lookup(
Call) ||
1237 AllocaMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1240 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1243 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1244 return Func &&
Func->hasAttr<OwnershipAttr>();
1247std::optional<ProgramStateRef>
1248MallocChecker::performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
1266 ASTContext &Ctx =
C.getASTContext();
1269 if (!KernelZeroFlagVal) {
1271 case llvm::Triple::FreeBSD:
1272 KernelZeroFlagVal = 0x0100;
1274 case llvm::Triple::NetBSD:
1275 KernelZeroFlagVal = 0x0002;
1277 case llvm::Triple::OpenBSD:
1278 KernelZeroFlagVal = 0x0008;
1280 case llvm::Triple::Linux:
1282 KernelZeroFlagVal = 0x8000;
1290 return std::nullopt;
1297 if (
Call.getNumArgs() < 2)
1298 return std::nullopt;
1300 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1301 const SVal
V =
C.getSVal(FlagsEx);
1305 return std::nullopt;
1308 NonLoc Flags =
V.castAs<NonLoc>();
1309 NonLoc ZeroFlag =
C.getSValBuilder()
1310 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1312 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1315 if (MaskedFlagsUC.isUnknownOrUndef())
1316 return std::nullopt;
1317 DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
1321 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1324 if (TrueState && !FalseState) {
1325 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1326 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1327 AllocationFamily(AF_Malloc));
1330 return std::nullopt;
1333SVal MallocChecker::evalMulForBufferSize(CheckerContext &
C,
const Expr *Blocks,
1334 const Expr *BlockBytes) {
1335 SValBuilder &SB =
C.getSValBuilder();
1336 SVal BlocksVal =
C.getSVal(Blocks);
1337 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1339 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1345 const CallEvent &
Call,
1346 CheckerContext &
C)
const {
1347 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1348 AllocationFamily(AF_Malloc));
1349 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1350 C.addTransition(State);
1354 const CallEvent &
Call,
1355 CheckerContext &
C)
const {
1356 std::optional<ProgramStateRef> MaybeState =
1357 performKernelMalloc(
Call,
C, State);
1359 State = *MaybeState;
1361 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1362 AllocationFamily(AF_Malloc));
1363 C.addTransition(State);
1387 bool ShouldFreeOnFail)
const {
1396 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1397 AllocationFamily(AF_Malloc));
1398 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1399 C.addTransition(State);
1403 CheckerContext &
C)
const {
1404 State = CallocMem(
C,
Call, State);
1405 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1406 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1407 C.addTransition(State);
1411 CheckerContext &
C)
const {
1412 bool IsKnownToBeAllocatedMemory =
false;
1413 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1415 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1416 AllocationFamily(AF_Malloc));
1417 C.addTransition(State);
1421 CheckerContext &
C)
const {
1422 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1423 AllocationFamily(AF_Alloca));
1424 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1425 C.addTransition(State);
1429 CheckerContext &
C)
const {
1430 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1433 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1434 AllocationFamily(AF_Malloc));
1436 C.addTransition(State);
1440 const CallEvent &
Call,
1441 CheckerContext &
C)
const {
1444 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1445 AllocationFamily(AF_IfNameIndex));
1447 C.addTransition(State);
1451 const CallEvent &
Call,
1452 CheckerContext &
C)
const {
1453 bool IsKnownToBeAllocatedMemory =
false;
1454 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1455 AllocationFamily(AF_IfNameIndex));
1456 C.addTransition(State);
1468 if (BuffType.isNull() || !BuffType->isVoidPointerType())
1474 const CallEvent &
Call,
1475 CheckerContext &
C)
const {
1476 bool IsKnownToBeAllocatedMemory =
false;
1477 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1487 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1490 auto RetVal = State->getSVal(BufArg,
Call.getLocationContext());
1491 State = State->BindExpr(CE,
C.getLocationContext(), RetVal);
1492 C.addTransition(State);
1498 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1499 AllocationFamily(AF_CXXNew));
1500 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1503 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1504 AllocationFamily(AF_CXXNewArray));
1505 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1508 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1509 AllocationFamily(AF_CXXNew));
1511 case OO_Array_Delete:
1512 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1513 AllocationFamily(AF_CXXNewArray));
1516 assert(
false &&
"not a new/delete operator");
1520 C.addTransition(State);
1524 CheckerContext &
C)
const {
1525 SValBuilder &svalBuilder =
C.getSValBuilder();
1527 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1528 AllocationFamily(AF_Malloc));
1529 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1530 C.addTransition(State);
1534 CheckerContext &
C)
const {
1535 State = MallocMemAux(
C,
Call,
Call.getArgExpr(1), UnknownVal(), State,
1536 AllocationFamily(AF_Malloc));
1537 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1538 C.addTransition(State);
1542 CheckerContext &
C)
const {
1543 SVal
Init = UndefinedVal();
1544 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1545 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1546 AllocationFamily(AF_Malloc));
1547 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1548 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1549 C.addTransition(State);
1553 CheckerContext &
C)
const {
1554 SValBuilder &SB =
C.getSValBuilder();
1556 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1557 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1558 AllocationFamily(AF_Malloc));
1559 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1560 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1561 C.addTransition(State);
1566 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1571 const CallEvent &
Call,
1572 CheckerContext &
C)
const {
1586 bool IsKnownToBeAllocated =
false;
1587 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1588 IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1591 C.addTransition(State);
1595 const CallEvent &
Call,
1596 CheckerContext &
C)
const {
1604 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1610 if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||
1611 SizeOpt->isUnknownOrUndef())
1614 const auto LinePtr = LinePtrOpt->getAs<DefinedSVal>();
1615 const auto Size = SizeOpt->getAs<DefinedSVal>();
1616 const MemRegion *LinePtrReg = LinePtr->getAsRegion();
1622 AllocationFamily(AF_Malloc), *LinePtr));
1626 CheckerContext &
C)
const {
1627 State = ReallocMemAux(
C,
Call,
false, State,
1628 AllocationFamily(AF_Malloc),
1630 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1631 State = ProcessZeroAllocCheck(
C,
Call, 2, State);
1632 C.addTransition(State);
1636 const CallEvent &
Call,
1637 CheckerContext &
C)
const {
1638 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1641 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1644 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1645 MismatchedDeallocatorChecker.isEnabled()) {
1650 switch (I->getOwnKind()) {
1651 case OwnershipAttr::Returns:
1652 State = MallocMemReturnsAttr(
C,
Call, I, State);
1654 case OwnershipAttr::Takes:
1655 case OwnershipAttr::Holds:
1656 State = FreeMemAttr(
C,
Call, I, State);
1661 C.addTransition(State);
1664bool MallocChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
1665 if (!
Call.getOriginExpr())
1670 if (
const CheckFn *Callback = FreeingMemFnMap.lookup(
Call)) {
1671 (*Callback)(
this, State,
Call,
C);
1675 if (
const CheckFn *Callback = AllocatingMemFnMap.lookup(
Call)) {
1676 State = MallocBindRetVal(
C,
Call, State,
false);
1677 (*Callback)(
this, State,
Call,
C);
1681 if (
const CheckFn *Callback = ReallocatingMemFnMap.lookup(
Call)) {
1682 State = MallocBindRetVal(
C,
Call, State,
false);
1683 (*Callback)(
this, State,
Call,
C);
1688 State = MallocBindRetVal(
C,
Call, State,
false);
1689 checkCXXNewOrCXXDelete(State,
Call,
C);
1694 checkCXXNewOrCXXDelete(State,
Call,
C);
1698 if (
const CheckFn *Callback = AllocaMemFnMap.lookup(
Call)) {
1699 State = MallocBindRetVal(
C,
Call, State,
true);
1700 (*Callback)(
this, State,
Call,
C);
1704 if (isFreeingOwnershipAttrCall(
Call)) {
1705 checkOwnershipAttr(State,
Call,
C);
1709 if (isAllocatingOwnershipAttrCall(
Call)) {
1710 State = MallocBindRetVal(
C,
Call, State,
false);
1711 checkOwnershipAttr(State,
Call,
C);
1720 CheckerContext &
C,
const CallEvent &
Call,
const unsigned IndexOfSizeArg,
1725 const Expr *Arg =
nullptr;
1727 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1728 Arg = CE->
getArg(IndexOfSizeArg);
1729 }
else if (
const CXXNewExpr *NE =
1730 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1731 if (
NE->isArray()) {
1732 Arg = *
NE->getArraySize();
1737 assert(
false &&
"not a CallExpr or CXXNewExpr");
1742 RetVal = State->getSVal(
Call.getOriginExpr(),
C.getLocationContext());
1747 State->getSVal(Arg,
Call.getLocationContext()).getAs<DefinedSVal>();
1754 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1758 std::tie(TrueState, FalseState) =
1759 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal,
Zero));
1761 if (TrueState && !FalseState) {
1762 SymbolRef Sym = RetVal->getAsLocSymbol();
1766 const RefState *RS = State->get<RegionState>(Sym);
1768 if (RS->isAllocated())
1769 return TrueState->set<RegionState>(
1770 Sym, RefState::getAllocatedOfSizeZero(RS));
1777 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1786 QualType Result =
T, PointeeType =
T->getPointeeType();
1787 while (!PointeeType.isNull()) {
1788 Result = PointeeType;
1789 PointeeType = PointeeType->getPointeeType();
1802 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1808 for (
const auto *CtorParam : CtorD->
parameters()) {
1811 if (CtorParamPointeeT.
isNull())
1824MallocChecker::processNewAllocation(
const CXXAllocatorCall &
Call,
1826 AllocationFamily Family)
const {
1830 const CXXNewExpr *
NE =
Call.getOriginExpr();
1831 const ParentMap &PM =
C.getLocationContext()->getParentMap();
1845 SVal
Target =
Call.getObjectUnderConstruction();
1846 if (
Call.getOriginExpr()->isArray()) {
1847 if (
auto SizeEx =
NE->getArraySize())
1848 checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1849 AllocationFamily(AF_CXXNewArray));
1853 State = ProcessZeroAllocCheck(
C,
Call, 0, State,
Target);
1857void MallocChecker::checkNewAllocator(
const CXXAllocatorCall &
Call,
1858 CheckerContext &
C)
const {
1859 if (!
C.wasInlined) {
1862 AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1864 C.addTransition(State);
1874 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1875 return FirstSlot ==
"dataWithBytesNoCopy" ||
1876 FirstSlot ==
"initWithBytesNoCopy" ||
1877 FirstSlot ==
"initWithCharactersNoCopy";
1884 for (
unsigned i = 1; i < S.
getNumArgs(); ++i)
1886 return !
Call.getArgSVal(i).isZeroConstant();
1888 return std::nullopt;
1891void MallocChecker::checkPostObjCMessage(
const ObjCMethodCall &
Call,
1892 CheckerContext &
C)
const {
1903 if (
Call.hasNonZeroCallbackArg())
1906 bool IsKnownToBeAllocatedMemory;
1908 true, IsKnownToBeAllocatedMemory,
1909 AllocationFamily(AF_Malloc),
1912 C.addTransition(State);
1916MallocChecker::MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
1917 const OwnershipAttr *Att,
1922 auto attrClassName = Att->getModule()->getName();
1923 auto Family = AllocationFamily(AF_Custom, attrClassName);
1925 if (!Att->args().empty()) {
1926 return MallocMemAux(
C,
Call,
1927 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1928 UnknownVal(), State, Family);
1930 return MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State, Family);
1934 const CallEvent &
Call,
1936 bool isAlloca)
const {
1937 const Expr *CE =
Call.getOriginExpr();
1943 unsigned Count =
C.blockCount();
1944 SValBuilder &SVB =
C.getSValBuilder();
1945 const LocationContext *LCtx =
C.getPredecessor()->getLocationContext();
1946 DefinedSVal RetVal =
1950 return State->BindExpr(CE,
C.getLocationContext(), RetVal);
1954 const CallEvent &
Call,
1955 const Expr *SizeEx, SVal
Init,
1957 AllocationFamily Family)
const {
1962 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
1965void MallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRef State,
1967 llvm::ArrayRef<SymbolRef> TaintedSyms,
1968 AllocationFamily Family)
const {
1969 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State,
this)) {
1971 std::make_unique<PathSensitiveBugReport>(TaintedAllocChecker, Msg, N);
1972 for (
const auto *TaintedSym : TaintedSyms) {
1973 R->markInteresting(TaintedSym);
1975 C.emitReport(std::move(R));
1979void MallocChecker::checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
1981 AllocationFamily Family)
const {
1984 std::vector<SymbolRef> TaintedSyms =
1986 if (TaintedSyms.empty())
1989 SValBuilder &SVB =
C.getSValBuilder();
1995 const llvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
1997 SVB.
makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));
1998 std::optional<NonLoc> SizeNL = SizeSVal.
getAs<NonLoc>();
1999 auto Cmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
2000 .
getAs<DefinedOrUnknownSVal>();
2003 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
2004 if (!StateTooLarge && StateNotTooLarge) {
2009 std::string
Callee =
"Memory allocation function";
2010 if (
Call.getCalleeIdentifier())
2011 Callee =
Call.getCalleeIdentifier()->getName().str();
2013 Callee +
" is called with a tainted (potentially attacker controlled) "
2014 "value. Make sure the value is bound checked.",
2015 State,
C, TaintedSyms, Family);
2019 const CallEvent &
Call, SVal Size,
2021 AllocationFamily Family)
const {
2025 const Expr *CE =
Call.getOriginExpr();
2030 "Allocation functions must return a pointer");
2032 const LocationContext *LCtx =
C.getPredecessor()->getLocationContext();
2033 SVal RetVal = State->getSVal(CE,
C.getLocationContext());
2036 State = State->bindDefaultInitial(RetVal,
Init, LCtx);
2040 Size = UnknownVal();
2042 checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
2046 Size.castAs<DefinedOrUnknownSVal>());
2053 AllocationFamily Family,
2054 std::optional<SVal> RetVal) {
2060 RetVal = State->getSVal(E,
C.getLocationContext());
2063 if (!RetVal->getAs<
Loc>())
2066 SymbolRef Sym = RetVal->getAsLocSymbol();
2074 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
2080 const CallEvent &
Call,
2081 const OwnershipAttr *Att,
2086 auto attrClassName = Att->getModule()->getName();
2087 auto Family = AllocationFamily(AF_Custom, attrClassName);
2089 bool IsKnownToBeAllocated =
false;
2091 for (
const auto &Arg : Att->args()) {
2093 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
2094 Att->getOwnKind() == OwnershipAttr::Holds,
2095 IsKnownToBeAllocated, Family);
2103 const CallEvent &
Call,
2105 bool Hold,
bool &IsKnownToBeAllocated,
2106 AllocationFamily Family,
2107 bool ReturnsNullOnFailure)
const {
2111 if (
Call.getNumArgs() < (
Num + 1))
2114 return FreeMemAux(
C,
Call.getArgExpr(
Num),
Call, State, Hold,
2115 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2122 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
2124 assert(*Ret &&
"We should not store the null return symbol");
2127 RetStatusSymbol = *Ret;
2135 const CallExpr *CE = dyn_cast<CallExpr>(E);
2146 if (I->getOwnKind() != OwnershipAttr::Takes)
2149 os <<
", which takes ownership of '" << I->getModule()->getName() <<
'\'';
2155 if (
const CallExpr *CE = dyn_cast<CallExpr>(E)) {
2171 if (Msg->isInstanceMessage())
2175 Msg->getSelector().print(os);
2179 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
2198 switch (Family.Kind) {
2205 case AF_CXXNewArray:
2208 case AF_IfNameIndex:
2209 os <<
"'if_nameindex()'";
2211 case AF_InnerBuffer:
2212 os <<
"container-specific allocator";
2215 os << Family.CustomName.value();
2219 assert(
false &&
"not a deallocation expression");
2224 switch (Family.Kind) {
2231 case AF_CXXNewArray:
2234 case AF_IfNameIndex:
2235 os <<
"'if_freenameindex()'";
2237 case AF_InnerBuffer:
2238 os <<
"container-specific deallocator";
2241 os <<
"function that takes ownership of '" << Family.CustomName.value()
2246 assert(
false &&
"not a deallocation expression");
2251MallocChecker::FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
2253 bool Hold,
bool &IsKnownToBeAllocated,
2254 AllocationFamily Family,
bool ReturnsNullOnFailure,
2255 std::optional<SVal> ArgValOpt)
const {
2260 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2263 DefinedOrUnknownSVal location = ArgVal.
castAs<DefinedOrUnknownSVal>();
2271 std::tie(notNullState, nullState) = State->assume(location);
2272 if (nullState && !notNullState)
2281 const Expr *ParentExpr =
Call.getOriginExpr();
2300 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2301 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2310 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2317 if (!R->
hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {
2326 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2332 const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->
getBaseRegion());
2339 const RefState *RsBase = State->get<RegionState>(SymBase);
2340 SymbolRef PreviousRetStatusSymbol =
nullptr;
2342 IsKnownToBeAllocated =
2343 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2348 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2354 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2356 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2357 SymBase, PreviousRetStatusSymbol);
2363 if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2364 RsBase->isEscaped()) {
2367 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2368 if (!DeallocMatchesAlloc) {
2370 RsBase, SymBase, Hold);
2380 const Expr *AllocExpr =
cast<Expr>(RsBase->getStmt());
2389 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2395 State = State->remove<FreeReturnValue>(SymBase);
2399 if (ReturnsNullOnFailure) {
2400 SVal RetVal =
C.getSVal(ParentExpr);
2402 if (RetStatusSymbol) {
2403 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2404 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2412 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2417 State = State->invalidateRegions({location},
Call.getCFGElementRef(),
2418 C.blockCount(),
C.getLocationContext(),
2424 return State->set<RegionState>(SymBase,
2425 RefState::getRelinquished(Family,
2428 return State->set<RegionState>(SymBase,
2429 RefState::getReleased(Family, ParentExpr));
2433const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family)
const {
2434 switch (Family.Kind) {
2438 case AF_IfNameIndex:
2439 return MallocChecker.getAs<
T>();
2441 case AF_CXXNewArray: {
2442 const T *ND = NewDeleteChecker.getAs<
T>();
2443 const T *NDL = NewDeleteLeaksChecker.getAs<
T>();
2446 if constexpr (std::is_same_v<T, CheckerFrontend>) {
2447 assert(ND && NDL &&
"Casting to CheckerFrontend always succeeds");
2449 return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;
2451 assert(!(ND && NDL) &&
2452 "NewDelete and NewDeleteLeaks must not share a bug type");
2453 return ND ? ND : NDL;
2455 case AF_InnerBuffer:
2456 return InnerPointerChecker.getAs<
T>();
2458 assert(
false &&
"no family");
2461 assert(
false &&
"unhandled family");
2465const T *MallocChecker::getRelevantFrontendAs(CheckerContext &
C,
2467 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2468 return MallocChecker.getAs<
T>();
2470 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2472 return getRelevantFrontendAs<T>(RS->getAllocationFamily());
2475bool MallocChecker::SummarizeValue(raw_ostream &os, SVal
V) {
2476 if (std::optional<nonloc::ConcreteInt> IntVal =
2477 V.getAs<nonloc::ConcreteInt>())
2478 os <<
"an integer (" << IntVal->getValue() <<
")";
2479 else if (std::optional<loc::ConcreteInt> ConstAddr =
2480 V.getAs<loc::ConcreteInt>())
2481 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2482 else if (std::optional<loc::GotoLabel> Label =
V.getAs<loc::GotoLabel>())
2483 os <<
"the address of the label '" << Label->getLabel()->getName() <<
"'";
2490bool MallocChecker::SummarizeRegion(
ProgramStateRef State, raw_ostream &os,
2491 const MemRegion *MR) {
2493 case MemRegion::FunctionCodeRegionKind: {
2496 os <<
"the address of the function '" << *FD <<
'\'';
2498 os <<
"the address of a function";
2501 case MemRegion::BlockCodeRegionKind:
2504 case MemRegion::BlockDataRegionKind:
2512 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2520 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2522 os <<
"the address of a local stack variable";
2527 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2535 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2537 os <<
"the address of a parameter";
2542 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2551 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2553 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2555 os <<
"the address of a global variable";
2564void MallocChecker::HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal,
2566 const Expr *DeallocExpr,
2567 AllocationFamily Family)
const {
2568 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2571 if (!Frontend->isEnabled()) {
2576 if (ExplodedNode *N =
C.generateErrorNode()) {
2577 SmallString<100> buf;
2578 llvm::raw_svector_ostream os(buf);
2581 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2582 MR = ER->getSuperRegion();
2584 os <<
"Argument to ";
2586 os <<
"deallocator";
2590 MR ? SummarizeRegion(
C.getState(), os, MR) : SummarizeValue(os, ArgVal);
2592 os <<
", which is not memory allocated by ";
2594 os <<
"not memory allocated by ";
2598 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2600 R->markInteresting(MR);
2602 C.emitReport(std::move(R));
2606void MallocChecker::HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
2607 SourceRange Range)
const {
2608 const FreeAlloca *Frontend;
2610 if (MallocChecker.isEnabled())
2611 Frontend = &MallocChecker;
2612 else if (MismatchedDeallocatorChecker.isEnabled())
2613 Frontend = &MismatchedDeallocatorChecker;
2619 if (ExplodedNode *N =
C.generateErrorNode()) {
2620 auto R = std::make_unique<PathSensitiveBugReport>(
2621 Frontend->FreeAllocaBug,
2622 "Memory allocated by 'alloca()' should not be deallocated", N);
2625 C.emitReport(std::move(R));
2629void MallocChecker::HandleMismatchedDealloc(CheckerContext &
C,
2631 const Expr *DeallocExpr,
2633 bool OwnershipTransferred)
const {
2634 if (!MismatchedDeallocatorChecker.isEnabled()) {
2639 if (ExplodedNode *N =
C.generateErrorNode()) {
2640 SmallString<100> buf;
2641 llvm::raw_svector_ostream os(buf);
2643 const Expr *AllocExpr =
cast<Expr>(RS->getStmt());
2644 SmallString<20> AllocBuf;
2645 llvm::raw_svector_ostream AllocOs(AllocBuf);
2646 SmallString<20> DeallocBuf;
2647 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2649 if (OwnershipTransferred) {
2651 os << DeallocOs.str() <<
" cannot";
2655 os <<
" take ownership of memory";
2658 os <<
" allocated by " << AllocOs.str();
2662 os <<
" allocated by " << AllocOs.str();
2664 os <<
" should be deallocated by ";
2668 os <<
", not " << DeallocOs.str();
2673 auto R = std::make_unique<PathSensitiveBugReport>(
2674 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);
2675 R->markInteresting(Sym);
2677 R->addVisitor<MallocBugVisitor>(Sym);
2678 C.emitReport(std::move(R));
2682void MallocChecker::HandleOffsetFree(CheckerContext &
C, SVal ArgVal,
2683 SourceRange Range,
const Expr *DeallocExpr,
2684 AllocationFamily Family,
2685 const Expr *AllocExpr)
const {
2686 const OffsetFree *Frontend = getRelevantFrontendAs<OffsetFree>(Family);
2689 if (!Frontend->isEnabled()) {
2694 ExplodedNode *N =
C.generateErrorNode();
2698 SmallString<100> buf;
2699 llvm::raw_svector_ostream os(buf);
2700 SmallString<20> AllocNameBuf;
2701 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2704 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2710 "Only symbols with a valid offset can have offset free errors");
2712 int offsetBytes = Offset.
getOffset() /
C.getASTContext().getCharWidth();
2714 os <<
"Argument to ";
2716 os <<
"deallocator";
2717 os <<
" is offset by "
2720 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2721 <<
" from the start of ";
2723 os <<
"memory allocated by " << AllocNameOs.str();
2725 os <<
"allocated memory";
2727 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->OffsetFreeBug,
2731 C.emitReport(std::move(R));
2734void MallocChecker::HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
2736 const UseFree *Frontend = getRelevantFrontendAs<UseFree>(
C, Sym);
2739 if (!Frontend->isEnabled()) {
2744 if (ExplodedNode *N =
C.generateErrorNode()) {
2745 AllocationFamily AF =
2746 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2748 auto R = std::make_unique<PathSensitiveBugReport>(
2749 Frontend->UseFreeBug,
2750 AF.Kind == AF_InnerBuffer
2751 ?
"Inner pointer of container used after re/deallocation"
2752 :
"Use of memory after it is released",
2755 R->markInteresting(Sym);
2757 R->addVisitor<MallocBugVisitor>(Sym);
2759 if (AF.Kind == AF_InnerBuffer)
2762 C.emitReport(std::move(R));
2766void MallocChecker::HandleDoubleFree(CheckerContext &
C, SourceRange Range,
2769 const DoubleFree *Frontend = getRelevantFrontendAs<DoubleFree>(
C, Sym);
2772 if (!Frontend->isEnabled()) {
2777 if (ExplodedNode *N =
C.generateErrorNode()) {
2778 auto R = std::make_unique<PathSensitiveBugReport>(
2779 Frontend->DoubleFreeBug,
2780 (Released ?
"Attempt to release already released memory"
2781 :
"Attempt to release non-owned memory"),
2783 if (
Range.isValid())
2785 R->markInteresting(Sym);
2787 R->markInteresting(PrevSym);
2788 R->addVisitor<MallocBugVisitor>(Sym);
2789 C.emitReport(std::move(R));
2793void MallocChecker::HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
2795 const UseZeroAllocated *Frontend =
2796 getRelevantFrontendAs<UseZeroAllocated>(
C, Sym);
2799 if (!Frontend->isEnabled()) {
2804 if (ExplodedNode *N =
C.generateErrorNode()) {
2805 auto R = std::make_unique<PathSensitiveBugReport>(
2806 Frontend->UseZeroAllocatedBug,
"Use of memory allocated with size zero",
2811 R->markInteresting(Sym);
2812 R->addVisitor<MallocBugVisitor>(Sym);
2814 C.emitReport(std::move(R));
2818void MallocChecker::HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal,
2820 const Expr *FreeExpr,
2821 AllocationFamily Family)
const {
2822 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2825 if (!Frontend->isEnabled()) {
2830 if (ExplodedNode *N =
C.generateErrorNode()) {
2831 SmallString<100> Buf;
2832 llvm::raw_svector_ostream Os(Buf);
2835 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2836 MR = ER->getSuperRegion();
2838 Os <<
"Argument to ";
2840 Os <<
"deallocator";
2842 Os <<
" is a function pointer";
2844 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2846 R->markInteresting(MR);
2848 C.emitReport(std::move(R));
2853MallocChecker::ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
2855 AllocationFamily Family,
bool SuffixWithN)
const {
2864 const Expr *arg0Expr = CE->
getArg(0);
2865 SVal Arg0Val =
C.getSVal(arg0Expr);
2868 DefinedOrUnknownSVal arg0Val = Arg0Val.
castAs<DefinedOrUnknownSVal>();
2870 SValBuilder &svalBuilder =
C.getSValBuilder();
2872 DefinedOrUnknownSVal PtrEQ = svalBuilder.
evalEQ(
2873 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2876 const Expr *Arg1 = CE->
getArg(1);
2879 SVal TotalSize =
C.getSVal(Arg1);
2881 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2886 DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(
2887 State, TotalSize.
castAs<DefinedOrUnknownSVal>(),
2888 svalBuilder.makeIntValWithWidth(
2889 svalBuilder.getContext().getCanonicalSizeType(), 0));
2892 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2894 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2897 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2898 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2902 if (PrtIsNull && !SizeIsZero) {
2904 C,
Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
2909 if (PrtIsNull && SizeIsZero)
2914 bool IsKnownToBeAllocated =
false;
2923 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2928 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2931 MallocMemAux(
C,
Call, TotalSize, UnknownVal(), stateFree, Family);
2935 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2936 if (ShouldFreeOnFail)
2937 Kind = OAR_FreeOnFailure;
2938 else if (!IsKnownToBeAllocated)
2939 Kind = OAR_DoNotTrackAfterFailure;
2943 SVal RetVal = stateRealloc->getSVal(CE,
C.getLocationContext());
2945 assert(FromPtr && ToPtr &&
2946 "By this point, FreeMemAux and MallocMemAux should have checked "
2947 "whether the argument or the return value is symbolic!");
2951 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2952 ReallocPair(FromPtr, Kind));
2954 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2955 return stateRealloc;
2961 const CallEvent &
Call,
2966 if (
Call.getNumArgs() < 2)
2969 SValBuilder &svalBuilder =
C.getSValBuilder();
2972 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2974 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State,
2975 AllocationFamily(AF_Malloc));
2978MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2980 CheckerContext &
C) {
2984 const ExplodedNode *AllocNode = N;
2985 const MemRegion *ReferenceRegion =
nullptr;
2989 if (!State->get<RegionState>(Sym))
2994 if (!ReferenceRegion) {
2995 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
2996 SVal Val = State->getSVal(MR);
3002 ReferenceRegion = MR;
3010 if (NContext == LeakContext ||
3016 return LeakInfo(AllocNode, ReferenceRegion);
3019void MallocChecker::HandleLeak(
SymbolRef Sym, ExplodedNode *N,
3020 CheckerContext &
C)
const {
3021 assert(N &&
"HandleLeak is only called with a non-null node");
3023 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3024 assert(RS &&
"cannot leak an untracked symbol");
3025 AllocationFamily Family = RS->getAllocationFamily();
3027 if (Family.Kind == AF_Alloca)
3030 const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);
3034 if (!Frontend || !Frontend->isEnabled())
3040 PathDiagnosticLocation LocUsedForUniqueing;
3041 const ExplodedNode *AllocNode =
nullptr;
3042 const MemRegion *Region =
nullptr;
3043 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
3048 C.getSourceManager(),
3051 SmallString<200> buf;
3052 llvm::raw_svector_ostream os(buf);
3054 os <<
"Potential leak of memory pointed to by ";
3057 os <<
"Potential memory leak";
3060 auto R = std::make_unique<PathSensitiveBugReport>(
3061 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3063 R->markInteresting(Sym);
3064 R->addVisitor<MallocBugVisitor>(Sym,
true);
3065 if (ShouldRegisterNoOwnershipChangeVisitor)
3066 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
3067 C.emitReport(std::move(R));
3070void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3071 CheckerContext &
C)
const
3074 RegionStateTy OldRS = state->get<RegionState>();
3075 RegionStateTy::Factory &F = state->get_context<RegionState>();
3077 RegionStateTy RS = OldRS;
3078 SmallVector<SymbolRef, 2> Errors;
3079 for (
auto [Sym, State] : RS) {
3080 if (SymReaper.
isDead(Sym)) {
3081 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3082 Errors.push_back(Sym);
3084 RS = F.remove(RS, Sym);
3090 assert(state->get<ReallocPairs>() ==
3091 C.getState()->get<ReallocPairs>());
3092 assert(state->get<FreeReturnValue>() ==
3093 C.getState()->get<FreeReturnValue>());
3098 ReallocPairsTy RP = state->get<ReallocPairs>();
3099 for (
auto [Sym, ReallocPair] : RP) {
3100 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
3101 state = state->remove<ReallocPairs>(Sym);
3106 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3107 for (
auto [Sym, RetSym] : FR) {
3108 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
3109 state = state->remove<FreeReturnValue>(Sym);
3114 ExplodedNode *N =
C.getPredecessor();
3115 if (!Errors.empty()) {
3116 N =
C.generateNonFatalErrorNode(
C.getState());
3119 HandleLeak(Sym, N,
C);
3124 C.addTransition(state->set<RegionState>(RS), N);
3131 return Name ==
"unique_ptr" || Name ==
"shared_ptr";
3138 if (
const auto *TST = QT->
getAs<TemplateSpecializationType>()) {
3139 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
3162 llvm::SmallPtrSetImpl<const MemRegion *> *
Out;
3165 llvm::SmallPtrSetImpl<const MemRegion *> &
Out)
3178 C->getState()->getLValue(BaseDecl,
Reg->getAs<
SubRegion>(), IsVirtual);
3183 return std::nullopt;
3199 std::optional<FieldConsumer> FC = std::nullopt) {
3212 BaseSpec.getType()->getAsCXXRecordDecl()) {
3213 std::optional<FieldConsumer> NewFC;
3215 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());
3233 if (!
T->isRecordType() ||
T->isReferenceType())
3265 const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(
Call.getDecl());
3269 const auto *RD = CD->getParent();
3274 for (
const auto *Param : CD->parameters()) {
3275 QualType ParamType = Param->getType();
3290 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {
3307 for (
unsigned I = 0, E = std::min(
Call.getNumArgs(), CD->getNumParams());
3309 const Expr *ArgExpr =
Call.getArgExpr(I);
3313 QualType ParamType = CD->getParamDecl(I)->
getType();
3317 SVal ArgVal =
Call.getArgSVal(I);
3319 if (Sym && State->contains<RegionState>(Sym)) {
3320 const RefState *RS = State->get<RegionState>(Sym);
3321 if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {
3322 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3338 return handleSmartPointerConstructorArguments(
Call, State);
3342 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;
3343 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3344 const Expr *AE =
Call.getArgExpr(I);
3353 SVal ArgVal =
Call.getArgSVal(I);
3354 const MemRegion *ArgRegion = ArgVal.
getAsRegion();
3357 SmartPtrFieldRoots);
3361 if (!SmartPtrFieldRoots.empty()) {
3362 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(
3363 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());
3364 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(
3365 SmartPtrFieldRootsVec, State);
3371void MallocChecker::checkPostCall(
const CallEvent &
Call,
3372 CheckerContext &
C)
const {
3374 if (
const auto *PostFN = PostFnMap.lookup(
Call)) {
3375 (*PostFN)(
this,
C.getState(),
Call,
C);
3380 C.addTransition(handleSmartPointerRelatedCalls(
Call,
C,
C.getState()));
3383void MallocChecker::checkPreCall(
const CallEvent &
Call,
3384 CheckerContext &
C)
const {
3386 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3387 const CXXDeleteExpr *DE = DC->getOriginExpr();
3393 if (!NewDeleteChecker.isEnabled())
3401 bool IsKnownToBeAllocated;
3404 false, IsKnownToBeAllocated,
3405 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3407 C.addTransition(State);
3418 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3419 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3423 HandleDoubleFree(
C, SourceRange(),
true, Sym,
3431 if (
const auto *PreFN = PreFnMap.lookup(
Call)) {
3432 (*PreFN)(
this,
C.getState(),
Call,
C);
3440 if (
const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&
Call)) {
3441 const FunctionDecl *FD = FC->getDecl();
3448 if (MallocChecker.isEnabled() && isFreeingCall(
Call))
3453 if (
const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&
Call)) {
3454 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3455 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3460 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3461 SVal ArgSVal =
Call.getArgSVal(I);
3466 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3472void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3473 CheckerContext &
C)
const {
3474 checkEscapeOnReturn(S,
C);
3480void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3481 CheckerContext &
C)
const {
3482 checkEscapeOnReturn(S,
C);
3485void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3486 CheckerContext &
C)
const {
3496 SVal RetVal =
C.getSVal(E);
3503 if (
const SymbolicRegion *BMR =
3505 Sym = BMR->getSymbol();
3509 checkUseAfterFree(Sym,
C, E);
3515void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3516 CheckerContext &
C)
const {
3524 const BlockDataRegion *R =
3528 if (ReferencedVars.empty())
3531 SmallVector<const MemRegion*, 10> Regions;
3532 const LocationContext *LC =
C.getLocationContext();
3533 MemRegionManager &MemMgr =
C.getSValBuilder().getRegionManager();
3535 for (
const auto &Var : ReferencedVars) {
3536 const VarRegion *VR = Var.getCapturedRegion();
3540 Regions.push_back(VR);
3544 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3545 C.addTransition(state);
3550 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3551 return (RS && RS->isReleased());
3554bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3555 const CallEvent &
Call, CheckerContext &
C)
const {
3556 if (
Call.getNumArgs() == 0)
3559 StringRef FunctionStr =
"";
3560 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3561 if (
const Stmt *Body = FD->
getBody())
3562 if (Body->getBeginLoc().isValid())
3566 C.getSourceManager(),
C.getLangOpts());
3569 if (!FunctionStr.contains(
"__isl_"))
3575 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3576 if (
const RefState *RS = State->get<RegionState>(Sym))
3577 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3579 C.addTransition(State);
3583bool MallocChecker::checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
3584 const Stmt *S)
const {
3594void MallocChecker::checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
3595 const Stmt *S)
const {
3598 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3599 if (RS->isAllocatedOfSizeZero())
3600 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3602 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3608void MallocChecker::checkLocation(SVal l,
bool isLoad,
const Stmt *S,
3609 CheckerContext &
C)
const {
3612 checkUseAfterFree(Sym,
C, S);
3613 checkUseZeroAllocated(Sym,
C, S);
3621 bool Assumption)
const {
3622 RegionStateTy RS = state->get<RegionState>();
3623 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3625 ConstraintManager &CMgr = state->getConstraintManager();
3626 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3628 state = state->remove<RegionState>(Sym);
3633 ReallocPairsTy RP = state->get<ReallocPairs>();
3634 for (
auto [Sym, ReallocPair] : RP) {
3636 ConstraintManager &CMgr = state->getConstraintManager();
3637 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3641 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3642 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3643 if (RS->isReleased()) {
3644 switch (ReallocPair.Kind) {
3645 case OAR_ToBeFreedAfterFailure:
3646 state = state->set<RegionState>(ReallocSym,
3647 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3649 case OAR_DoNotTrackAfterFailure:
3650 state = state->remove<RegionState>(ReallocSym);
3653 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3657 state = state->remove<ReallocPairs>(Sym);
3663bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3664 const CallEvent *
Call,
3668 EscapingSymbol =
nullptr;
3678 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(
Call)) {
3681 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3694 return *FreeWhenDone;
3700 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3701 if (FirstSlot.ends_with(
"NoCopy"))
3708 if (FirstSlot.starts_with(
"addPointer") ||
3709 FirstSlot.starts_with(
"insertPointer") ||
3710 FirstSlot.starts_with(
"replacePointer") ||
3711 FirstSlot ==
"valueWithPointer") {
3718 if (Msg->getMethodFamily() ==
OMF_init) {
3719 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3735 if (isMemCall(*
Call))
3739 if (!
Call->isInSystemHeader())
3746 StringRef FName = II->
getName();
3750 if (FName.ends_with(
"NoCopy")) {
3754 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3755 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3756 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3757 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3758 if (DeallocatorName ==
"kCFAllocatorNull")
3769 if (FName ==
"funopen")
3770 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3776 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3777 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3778 if (
Call->getNumArgs() >= 1) {
3780 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3781 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3782 if (D->getCanonicalDecl()->getName().contains(
"std"))
3792 if (FName ==
"CGBitmapContextCreate" ||
3793 FName ==
"CGBitmapContextCreateWithData" ||
3794 FName ==
"CVPixelBufferCreateWithBytes" ||
3795 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3796 FName ==
"OSAtomicEnqueue") {
3800 if (FName ==
"postEvent" &&
3805 if (FName ==
"connectImpl" &&
3810 if (FName ==
"singleShotImpl" &&
3819 if (
Call->argumentsMayEscape())
3829 const CallEvent *
Call,
3831 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3837 const CallEvent *
Call,
3840 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3845 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3846 RS->getAllocationFamily().Kind == AF_CXXNew);
3852 bool IsConstPointerEscape)
const {
3857 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3864 if (EscapingSymbol && EscapingSymbol != sym)
3867 if (
const RefState *RS = State->get<RegionState>(sym))
3868 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3870 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3875bool MallocChecker::isArgZERO_SIZE_PTR(
ProgramStateRef State, CheckerContext &
C,
3876 SVal ArgVal)
const {
3877 if (!KernelZeroSizePtrValue)
3878 KernelZeroSizePtrValue =
3881 const llvm::APSInt *ArgValKnown =
3882 C.getSValBuilder().getKnownValue(State, ArgVal);
3883 return ArgValKnown && *KernelZeroSizePtrValue &&
3884 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3889 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3890 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3892 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3894 if (!currMap.lookup(sym))
3904 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3905 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3906 N.contains_insensitive(
"intrusive") ||
3907 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3916 BugReporterContext &BRC,
3917 PathSensitiveBugReport &BR) {
3921 const RefState *RSCurr = state->get<RegionState>(Sym);
3922 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3927 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3940 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
3942 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3945 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3946 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3952 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
3955 if (
const auto *MD =
3957 const CXXRecordDecl *RD = MD->getParent();
3975 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3976 SmallString<256> Buf;
3977 llvm::raw_svector_ostream
OS(Buf);
3980 if (isAllocated(RSCurr, RSPrev, S)) {
3981 Msg =
"Memory is allocated";
3982 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3983 Sym,
"Returned allocated memory");
3985 const auto Family = RSCurr->getAllocationFamily();
3986 switch (Family.Kind) {
3991 case AF_CXXNewArray:
3992 case AF_IfNameIndex:
3993 Msg =
"Memory is released";
3994 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3995 Sym,
"Returning; memory was released");
3997 case AF_InnerBuffer: {
3998 const MemRegion *ObjRegion =
4001 QualType ObjTy = TypedRegion->getValueType();
4002 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
4005 OS <<
"deallocated by call to destructor";
4006 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4007 Sym,
"Returning; inner buffer was deallocated");
4009 OS <<
"reallocated by call to '";
4010 const Stmt *S = RSCurr->getStmt();
4011 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
4012 OS << MemCallE->getMethodDecl()->getDeclName();
4013 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
4014 OS << OpCallE->getDirectCallee()->getDeclName();
4015 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
4017 CallEventRef<>
Call =
4019 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
4020 OS << D->getDeclName();
4025 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4026 Sym,
"Returning; inner buffer was reallocated");
4032 assert(
false &&
"Unhandled allocation family!");
4045 for (
const LocationContext *LC = CurrentLC; LC; LC = LC->
getParent()) {
4046 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
4086 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
4087 Msg =
"Memory ownership is transferred";
4088 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
4089 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
4090 Mode = ReallocationFailed;
4091 Msg =
"Reallocation failed";
4092 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
4093 Sym,
"Reallocation failed");
4097 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
4098 "We only support one failed realloc at a time.");
4100 FailedReallocSymbol = sym;
4105 }
else if (Mode == ReallocationFailed) {
4106 assert(FailedReallocSymbol &&
"No symbol to look for.");
4109 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
4111 Msg =
"Attempt to reallocate memory";
4112 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4113 Sym,
"Returned reallocated memory");
4114 FailedReallocSymbol =
nullptr;
4127 PathDiagnosticLocation Pos;
4129 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
4133 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
4140 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
4145void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
4146 const char *NL,
const char *Sep)
const {
4148 RegionStateTy RS = State->get<RegionState>();
4150 if (!RS.isEmpty()) {
4151 Out << Sep <<
"MallocChecker :" << NL;
4152 for (
auto [Sym,
Data] : RS) {
4153 const RefState *RefS = State->get<RegionState>(Sym);
4154 AllocationFamily Family = RefS->getAllocationFamily();
4156 const CheckerFrontend *Frontend =
4157 getRelevantFrontendAs<CheckerFrontend>(Family);
4171namespace allocation_state {
4175 AllocationFamily Family(AF_InnerBuffer);
4176 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
4186 Mgr.
getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);
4194 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
4196 Chk->ShouldRegisterNoOwnershipChangeVisitor =
4198 DMMName,
"AddNoOwnershipChangeNotes");
4201bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
4205#define REGISTER_CHECKER(NAME) \
4206 void ento::register##NAME(CheckerManager &Mgr) { \
4207 Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr); \
4210 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
#define REGISTER_CHECKER(name)
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 isRvalueByValueRecordWithSmartPtr(const Expr *AE)
Check if an expression is an rvalue record with smart owning pointer fields passed by value.
static bool isFromStdNamespace(const CallEvent &Call)
static bool isStandardNew(const FunctionDecl *FD)
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 void collectSmartPtrFieldRegions(const MemRegion *Reg, QualType RecQT, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
Collect memory regions of smart owning pointer fields from a record type (including fields from base ...
static bool hasSmartPtrField(const CXXRecordDecl *CRD, std::optional< FieldConsumer > FC=std::nullopt)
Check if a record type has smart owning pointer fields (directly or in base classes).
static bool isStandardDelete(const FunctionDecl *FD)
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static bool isSmartPtrType(QualType QT)
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 isRvalueByValueRecord(const Expr *AE)
Check if an expression is an rvalue record type passed by value.
#define BUGTYPE_PROVIDER(NAME, DEF)
static bool isGRealloc(const CallEvent &Call)
static const Expr * getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD)
static bool isSmartPtrRecord(const CXXRecordDecl *RD)
Check if a CXXRecordDecl has a name matching recognized smart pointer names.
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 isSmartPtrCall(const CallEvent &Call)
Check if a call is a constructor of a smart owning pointer class that accepts pointer parameters.
static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)
Checks if the previous call to free on the given symbol failed - if free failed, returns true.
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)
Update the RefState to reflect the new memory allocation.
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
static bool isSmartPtrName(StringRef Name)
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.
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()
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
CanQualType getCanonicalSizeType() const
CanQualType UnsignedLongTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
const BlockDecl * getBlockDecl() const
Represents a base class of a C++ class.
Represents binding an expression to a temporary.
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.
Represents a C++ functional cast expression that builds a temporary object.
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)
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
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Represents a member of a struct/union/class.
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.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Describes an C or C++ initializer list.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
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
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.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
field_range fields() const
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
unsigned getNumArgs() const
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.
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.
The base class of all kinds of template declarations (e.g., class, function, etc.).
NamedDecl * getTemplatedDecl() const
Get the underlying, templated declaration.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isVoidPointerType() const
bool isFunctionPointerType() const
bool isPointerType() const
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
APSIntPtr getMaxValue(const llvm::APSInt &v)
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.
An immutable map from CallDescriptions to arbitrary data.
CallEventRef getSimpleCall(const CallExpr *E, ProgramStateRef State, const LocationContext *LCtx, CFGBlock::ConstCFGElementRef ElemRef)
Represents an abstract call to a function or method along a particular path.
Checker families (where a single backend class implements multiple related frontends) should derive f...
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
CheckerNameRef getName() const
const AnalyzerOptions & getAnalyzerOptions() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
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...
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.
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
bool hasMemorySpace(ProgramStateRef State) const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
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.
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()
bool hasSymbolicOffset() const
int64_t getOffset() const
DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned Count)
Conjure a symbol representing heap allocated memory 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...
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.
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
virtual void dumpToStream(raw_ostream &os) const
virtual QualType getType() const =0
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
SymbolRef getSymbol() const
It might return null.
const VarDecl * getDecl() const override=0
const StackFrameContext * getStackFrame() const
It might return null.
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.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
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.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
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)
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
bool isa(CodeGen::Address addr)
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
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.
U cast(CodeGen::Address addr)
@ Other
Other implicit parameter.
int const char * function
Helper struct for collecting smart owning pointer field regions.
void consume(const FieldDecl *FD)
std::optional< FieldConsumer > switchToBase(const CXXRecordDecl *BaseDecl, bool IsVirtual)
FieldConsumer(const MemRegion *Reg, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
llvm::SmallPtrSetImpl< const MemRegion * > * Out