84#include "llvm/ADT/STLExtras.h"
85#include "llvm/ADT/SmallVector.h"
86#include "llvm/ADT/StringExtras.h"
87#include "llvm/Support/Casting.h"
88#include "llvm/Support/Compiler.h"
89#include "llvm/Support/ErrorHandling.h"
90#include "llvm/Support/raw_ostream.h"
97using namespace std::placeholders;
109enum AllocationFamilyKind {
120struct AllocationFamily {
121 AllocationFamilyKind Kind;
122 std::optional<StringRef> CustomName;
124 explicit AllocationFamily(AllocationFamilyKind AKind,
125 std::optional<StringRef> Name = std::nullopt)
126 : Kind(AKind), CustomName(Name) {
127 assert((Kind != AF_Custom || CustomName.has_value()) &&
128 "Custom family must specify also the name");
131 if (Kind == AF_Custom && CustomName.value() ==
"malloc") {
133 CustomName = std::nullopt;
138 return std::tie(Kind, CustomName) == std::tie(
Other.Kind,
Other.CustomName);
142 return !(*
this ==
Other);
145 void Profile(llvm::FoldingSetNodeID &ID)
const {
148 if (Kind == AF_Custom)
149 ID.AddString(CustomName.value());
194 AllocationFamily Family;
196 RefState(Kind k,
const Stmt *s, AllocationFamily family)
197 : S(s), K(k), Family(family) {
198 assert(family.Kind != AF_None);
202 bool isAllocated()
const {
return K == Allocated; }
203 bool isAllocatedOfSizeZero()
const {
return K == AllocatedOfSizeZero; }
204 bool isReleased()
const {
return K == Released; }
205 bool isRelinquished()
const {
return K == Relinquished; }
206 bool isEscaped()
const {
return K == Escaped; }
207 AllocationFamily getAllocationFamily()
const {
return Family; }
208 const Stmt *getStmt()
const {
return S; }
211 return K ==
X.K && S ==
X.S && Family ==
X.Family;
214 static RefState getAllocated(AllocationFamily family,
const Stmt *s) {
215 return RefState(Allocated, s, family);
217 static RefState getAllocatedOfSizeZero(
const RefState *RS) {
218 return RefState(AllocatedOfSizeZero, RS->getStmt(),
219 RS->getAllocationFamily());
221 static RefState getReleased(AllocationFamily family,
const Stmt *s) {
222 return RefState(Released, s, family);
224 static RefState getRelinquished(AllocationFamily family,
const Stmt *s) {
225 return RefState(Relinquished, s, family);
227 static RefState getEscaped(
const RefState *RS) {
228 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
231 void Profile(llvm::FoldingSetNodeID &ID)
const {
237 LLVM_DUMP_METHOD
void dump(raw_ostream &
OS)
const {
239#define CASE(ID) case ID: OS << #ID; break;
241 CASE(AllocatedOfSizeZero)
248 LLVM_DUMP_METHOD
void dump()
const {
dump(llvm::errs()); }
263 AllocationFamily Family,
264 std::optional<SVal> RetVal = std::nullopt);
278enum OwnershipAfterReallocKind {
280 OAR_ToBeFreedAfterFailure,
290 OAR_DoNotTrackAfterFailure
303 OwnershipAfterReallocKind Kind;
305 ReallocPair(
SymbolRef S, OwnershipAfterReallocKind K)
306 : ReallocatedSym(S), Kind(K) {}
307 void Profile(llvm::FoldingSetNodeID &ID)
const {
309 ID.AddPointer(ReallocatedSym);
312 return ReallocatedSym ==
X.ReallocatedSym &&
348#define BUGTYPE_PROVIDER(NAME, DEF) \
349 struct NAME : virtual public CheckerFrontend { \
350 BugType NAME##Bug{this, DEF, categories::MemoryError}; \
372#undef BUGTYPE_PROVIDER
374template <
typename... BT_PROVIDERS>
375struct DynMemFrontend :
virtual public CheckerFrontend,
public BT_PROVIDERS... {
376 template <
typename T>
const T *getAs()
const {
377 if constexpr (std::is_same_v<T, CheckerFrontend> ||
378 (std::is_same_v<T, BT_PROVIDERS> || ...))
379 return static_cast<const T *
>(
this);
390 check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape,
391 check::PreStmt<ReturnStmt>, check::EndFunction, check::PreCall,
392 check::PostCall, eval::Call, check::NewAllocator,
393 check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location,
400 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
402 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
410 bool ModelAllocationFailure =
false;
419 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
422 DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
424 DynMemFrontend<Leak> NewDeleteLeaksChecker;
425 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
426 DynMemFrontend<UseFree> InnerPointerChecker;
429 CheckerFrontendWithBugType TaintedAllocChecker{
"Tainted Memory Allocation",
432 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
434 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
435 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
436 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
439 handleSmartPointerConstructorArguments(
const CallEvent &
Call,
444 void checkNewAllocator(
const CXXAllocatorCall &
Call, CheckerContext &
C)
const;
445 void checkPostObjCMessage(
const ObjCMethodCall &
Call, CheckerContext &
C)
const;
446 void checkPostStmt(
const BlockExpr *BE, CheckerContext &
C)
const;
447 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &
C)
const;
448 void checkPreStmt(
const ReturnStmt *S, CheckerContext &
C)
const;
449 void checkEndFunction(
const ReturnStmt *S, CheckerContext &
C)
const;
451 bool Assumption)
const;
452 void checkLocation(SVal l,
bool isLoad,
const Stmt *S,
453 CheckerContext &
C)
const;
457 const CallEvent *
Call,
461 const CallEvent *
Call,
465 const char *NL,
const char *Sep)
const override;
467 StringRef getDebugTag()
const override {
return "MallocChecker"; }
470#define CHECK_FN(NAME) \
471 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
503 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},
504 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},
507 const CallDescriptionMap<CheckFn> PostFnMap{
510 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},
511 {{CDM::CLibrary, {
"getdelim"}, 4},
512 &MallocChecker::checkGetDelimOrGetLine},
515 const CallDescriptionMap<CheckFn> FreeingMemFnMap{
516 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
517 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
518 &MallocChecker::checkIfFreeNameIndex},
519 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
520 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
523 bool isFreeingCall(
const CallEvent &
Call)
const;
524 static bool isFreeingOwnershipAttrCall(
const FunctionDecl *
Func);
525 static bool isFreeingOwnershipAttrCall(
const CallEvent &
Call);
526 static bool isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func);
527 static bool isAllocatingOwnershipAttrCall(
const CallEvent &
Call);
529 friend class NoMemOwnershipChangeVisitor;
531 CallDescriptionMap<CheckFn> AllocaMemFnMap{
532 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
533 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
537 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
538 &MallocChecker::checkAlloca},
541 CallDescriptionMap<CheckFn> AllocatingMemFnMap{
542 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAllocMayFail},
543 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
544 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
545 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
546 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
547 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
548 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
549 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
550 {{CDM::CLibrary, {
"if_nameindex"}, 0}, &MallocChecker::checkIfNameIndex},
551 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
552 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
553 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
554 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
555 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
556 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
557 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
558 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
559 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
560 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
561 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
564 CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
565 {{CDM::CLibrary, {
"realloc"}, 2},
566 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
567 {{CDM::CLibrary, {
"reallocf"}, 2},
568 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
true)},
569 {{CDM::CLibrary, {
"g_realloc"}, 2},
570 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
571 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
572 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
573 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
574 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
577 bool isMemCall(
const CallEvent &
Call)
const;
578 bool hasOwnershipReturns(
const CallEvent &
Call)
const;
579 bool hasOwnershipTakesHolds(
const CallEvent &
Call)
const;
580 void reportTaintBug(StringRef Msg,
ProgramStateRef State, CheckerContext &
C,
581 llvm::ArrayRef<SymbolRef> TaintedSyms,
582 AllocationFamily Family)
const;
584 void checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
586 AllocationFamily Family)
const;
589 mutable std::optional<uint64_t> KernelZeroFlagVal;
591 using KernelZeroSizePtrValueTy = std::optional<int>;
596 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
601 processNewAllocation(
const CXXAllocatorCall &
Call, CheckerContext &
C,
602 AllocationFamily Family)
const;
613 ProcessZeroAllocCheck(CheckerContext &
C,
const CallEvent &
Call,
615 std::optional<SVal> RetVal = std::nullopt);
634 MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
644 const CallEvent &
Call,
646 bool isAlloca)
const;
658 MallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
const Expr *SizeEx,
671 const CallEvent &
Call, SVal Size,
673 AllocationFamily Family)
const;
686 llvm::ArrayRef<unsigned> SizeArgIndexes = {})
const;
690 [[nodiscard]] std::optional<ProgramStateRef>
691 performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
712 const CallEvent &
Call,
713 const OwnershipAttr *Att,
737 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
738 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
762 FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
const CallEvent &
Call,
764 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
765 std::optional<SVal> ArgValOpt = {})
const;
781 ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
bool ShouldFreeOnFail,
783 bool SuffixWithN =
false)
const;
790 [[nodiscard]]
static SVal evalMulForBufferSize(CheckerContext &
C,
792 const Expr *BlockBytes);
800 const CallEvent &
Call,
805 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
806 CheckerContext &
C)
const;
809 bool checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
const Stmt *S)
const;
813 void checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
814 const Stmt *S)
const;
826 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
835 bool IsConstPointerEscape)
const;
838 void checkEscapeOnReturn(
const ReturnStmt *S, CheckerContext &
C)
const;
847 const T *getRelevantFrontendAs(AllocationFamily Family)
const;
850 const T *getRelevantFrontendAs(CheckerContext &
C,
SymbolRef Sym)
const;
852 static bool SummarizeValue(raw_ostream &os, SVal
V);
854 const MemRegion *MR);
856 void HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal, SourceRange Range,
857 const Expr *DeallocExpr,
858 AllocationFamily Family)
const;
860 void HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
861 SourceRange Range)
const;
863 void HandleMismatchedDealloc(CheckerContext &
C, SourceRange Range,
864 const Expr *DeallocExpr,
const RefState *RS,
865 SymbolRef Sym,
bool OwnershipTransferred)
const;
867 void HandleOffsetFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
868 const Expr *DeallocExpr, AllocationFamily Family,
869 const Expr *AllocExpr =
nullptr)
const;
871 void HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
874 void HandleDoubleFree(CheckerContext &
C, SourceRange Range,
bool Released,
877 void HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
880 void HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
881 const Expr *FreeExpr,
882 AllocationFamily Family)
const;
886 static LeakInfo getAllocationSite(
const ExplodedNode *N,
SymbolRef Sym,
889 void HandleLeak(
SymbolRef Sym, ExplodedNode *N, CheckerContext &
C)
const;
902class NoMemOwnershipChangeVisitor final :
public NoOwnershipChangeVisitor {
911 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
912 const auto *MallocChk =
static_cast<const MallocChecker *
>(&Checker);
913 if (MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
914 MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
917 if (
const auto *
Func =
918 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
919 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
926 return CallEnterState->get<RegionState>(Sym) !=
927 CallExitEndState->get<RegionState>(Sym);
934 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
935 ASTContext &ACtx)
final {
936 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
946 using namespace clang::ast_matchers;
951 for (BoundNodes
Match : Matches) {
952 if (
Match.getNodeAs<CXXDeleteExpr>(
"delete"))
955 if (
const auto *
Call =
Match.getNodeAs<CallExpr>(
"call"))
956 if (isFreeingCallAsWritten(*
Call))
968 N->getState()->getStateManager().getContext().getSourceManager());
969 return std::make_shared<PathDiagnosticEventPiece>(
970 L,
"Returning without deallocating memory or storing the pointer for "
971 "later deallocation");
975 NoMemOwnershipChangeVisitor(
SymbolRef Sym,
const MallocChecker *Checker)
976 : NoOwnershipChangeVisitor(Sym, Checker) {}
978 void Profile(llvm::FoldingSetNodeID &ID)
const override {
997 enum NotificationMode { Normal, ReallocationFailed };
1003 NotificationMode Mode;
1010 const StackFrame *ReleaseFunctionSF;
1015 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
1016 : Sym(S), Mode(Normal), FailedReallocSymbol(
nullptr),
1017 ReleaseFunctionSF(
nullptr), IsLeak(isLeak) {}
1019 static void *getTag() {
1024 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1025 ID.AddPointer(getTag());
1030 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
1032 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
1034 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1036 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1041 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
1044 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
1045 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
1046 (!Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
1051 static inline bool isRelinquished(
const RefState *RSCurr,
1052 const RefState *RSPrev,
const Stmt *Stmt) {
1054 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
1055 (RSCurr && RSCurr->isRelinquished()) &&
1056 (!RSPrev || !RSPrev->isRelinquished()));
1063 static inline bool hasReallocFailed(
const RefState *RSCurr,
1064 const RefState *RSPrev,
1066 return ((!isa_and_nonnull<CallExpr>(Stmt)) &&
1068 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1070 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1074 BugReporterContext &BRC,
1075 PathSensitiveBugReport &BR)
override;
1078 const ExplodedNode *EndPathNode,
1079 PathSensitiveBugReport &BR)
override {
1085 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1090 class StackHintGeneratorForReallocationFailed
1091 :
public StackHintGeneratorForSymbol {
1093 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1094 : StackHintGeneratorForSymbol(S, M) {}
1096 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1100 SmallString<200> buf;
1101 llvm::raw_svector_ostream os(buf);
1103 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1104 <<
" parameter failed";
1106 return std::string(os.str());
1109 std::string getMessageForReturn(
const CallExpr *CallExpr)
override {
1110 return "Reallocation of returned value failed";
1128 bool VisitSymbol(
SymbolRef sym)
override {
1129 state = state->remove<RegionState>(sym);
1149 explicit EscapeTrackedCallback(
ProgramStateRef S) : State(std::move(S)) {}
1152 bool VisitSymbol(
SymbolRef Sym)
override {
1153 if (
const RefState *RS = State->get<RegionState>(Sym)) {
1154 if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) {
1155 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
1163 EscapeTrackedRegionsReachableFrom(ArrayRef<const MemRegion *> Roots,
1170 SmallVector<const MemRegion *, 10> Regions;
1171 EscapeTrackedCallback Visitor(State);
1172 for (
const MemRegion *R : Roots) {
1173 Regions.push_back(R);
1175 State->scanReachableSymbols(Regions, Visitor);
1176 return Visitor.State;
1179 friend class SymbolVisitor;
1188 if (Kind != OO_New && Kind != OO_Array_New)
1204 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1215 return L.
isInvalid() || (!HasBody &&
SM.isInSystemHeader(L));
1222bool MallocChecker::isFreeingOwnershipAttrCall(
const CallEvent &
Call) {
1223 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1225 return Func && isFreeingOwnershipAttrCall(
Func);
1228bool MallocChecker::isFreeingOwnershipAttrCall(
const FunctionDecl *
Func) {
1229 if (
Func->hasAttrs()) {
1230 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1231 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1232 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1239bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1243 return isFreeingOwnershipAttrCall(
Call);
1246bool MallocChecker::isAllocatingOwnershipAttrCall(
const CallEvent &
Call) {
1247 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1249 return Func && isAllocatingOwnershipAttrCall(
Func);
1252bool MallocChecker::isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func) {
1253 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1254 if (I->getOwnKind() == OwnershipAttr::Returns)
1261bool MallocChecker::isMemCall(
const CallEvent &
Call)
const {
1266 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1269 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1270 return Func &&
Func->hasAttr<OwnershipAttr>();
1273std::optional<ProgramStateRef>
1274MallocChecker::performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
1292 ASTContext &Ctx =
C.getASTContext();
1295 if (!KernelZeroFlagVal) {
1297 case llvm::Triple::FreeBSD:
1298 KernelZeroFlagVal = 0x0100;
1300 case llvm::Triple::NetBSD:
1301 KernelZeroFlagVal = 0x0002;
1303 case llvm::Triple::OpenBSD:
1304 KernelZeroFlagVal = 0x0008;
1306 case llvm::Triple::Linux:
1308 KernelZeroFlagVal = 0x8000;
1316 return std::nullopt;
1323 if (
Call.getNumArgs() < 2)
1324 return std::nullopt;
1326 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1327 const SVal
V =
C.getSVal(FlagsEx);
1331 return std::nullopt;
1334 NonLoc Flags =
V.castAs<NonLoc>();
1335 NonLoc ZeroFlag =
C.getSValBuilder()
1336 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1338 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1341 if (MaskedFlagsUC.isUnknownOrUndef())
1342 return std::nullopt;
1343 DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
1347 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1350 if (TrueState && !FalseState) {
1351 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1352 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1353 AllocationFamily(AF_Malloc));
1356 return std::nullopt;
1359SVal MallocChecker::evalMulForBufferSize(CheckerContext &
C,
const Expr *Blocks,
1360 const Expr *BlockBytes) {
1361 SValBuilder &SB =
C.getSValBuilder();
1362 SVal BlocksVal =
C.getSVal(Blocks);
1363 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1365 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1371 const CallEvent &
Call,
1372 CheckerContext &
C)
const {
1373 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1374 AllocationFamily(AF_Malloc));
1375 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1376 C.addTransition(State);
1380 const CallEvent &
Call,
1381 CheckerContext &
C)
const {
1382 C.addTransition(FailedAlloc(
C,
Call, State, {0}));
1384 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1385 AllocationFamily(AF_Malloc));
1386 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1387 C.addTransition(State);
1391 const CallEvent &
Call,
1392 CheckerContext &
C)
const {
1393 std::optional<ProgramStateRef> MaybeState =
1394 performKernelMalloc(
Call,
C, State);
1396 State = *MaybeState;
1398 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1399 AllocationFamily(AF_Malloc));
1400 C.addTransition(State);
1424 bool ShouldFreeOnFail)
const {
1434 if (StandardRealloc)
1435 C.addTransition(FailedAlloc(
C,
Call, State, {1}));
1437 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1438 AllocationFamily(AF_Malloc));
1439 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1440 C.addTransition(State);
1444 CheckerContext &
C)
const {
1445 C.addTransition(FailedAlloc(
C,
Call, State, {0, 1}));
1447 State = CallocMem(
C,
Call, State);
1448 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1449 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1450 C.addTransition(State);
1454 CheckerContext &
C)
const {
1455 bool IsKnownToBeAllocatedMemory =
false;
1456 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1458 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1459 AllocationFamily(AF_Malloc));
1460 C.addTransition(State);
1464 CheckerContext &
C)
const {
1465 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1466 AllocationFamily(AF_Alloca));
1467 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1468 C.addTransition(State);
1472 CheckerContext &
C)
const {
1473 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1477 C.addTransition(FailedAlloc(
C,
Call, State));
1479 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1480 AllocationFamily(AF_Malloc));
1481 C.addTransition(State);
1485 const CallEvent &
Call,
1486 CheckerContext &
C)
const {
1487 C.addTransition(FailedAlloc(
C,
Call, State));
1491 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1492 AllocationFamily(AF_IfNameIndex));
1493 C.addTransition(State);
1497 const CallEvent &
Call,
1498 CheckerContext &
C)
const {
1499 bool IsKnownToBeAllocatedMemory =
false;
1500 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1501 AllocationFamily(AF_IfNameIndex));
1502 C.addTransition(State);
1514 if (BuffType.isNull() || !BuffType->isVoidPointerType())
1520 const CallEvent &
Call,
1521 CheckerContext &
C)
const {
1522 bool IsKnownToBeAllocatedMemory =
false;
1523 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1533 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1536 auto RetVal = State->getSVal(BufArg,
Call.getStackFrame());
1537 State = State->BindExpr(CE,
C.getStackFrame(), RetVal);
1538 C.addTransition(State);
1544 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1545 AllocationFamily(AF_CXXNew));
1546 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1549 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1550 AllocationFamily(AF_CXXNewArray));
1551 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1554 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1555 AllocationFamily(AF_CXXNew));
1557 case OO_Array_Delete:
1558 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1559 AllocationFamily(AF_CXXNewArray));
1562 assert(
false &&
"not a new/delete operator");
1566 C.addTransition(State);
1570 CheckerContext &
C)
const {
1571 SValBuilder &svalBuilder =
C.getSValBuilder();
1573 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1574 AllocationFamily(AF_Malloc));
1575 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1576 C.addTransition(State);
1580 CheckerContext &
C)
const {
1581 State = MallocMemAux(
C,
Call,
Call.getArgExpr(1), UnknownVal(), State,
1582 AllocationFamily(AF_Malloc));
1583 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1584 C.addTransition(State);
1588 CheckerContext &
C)
const {
1589 SVal
Init = UndefinedVal();
1590 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1591 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1592 AllocationFamily(AF_Malloc));
1593 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1594 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1595 C.addTransition(State);
1599 CheckerContext &
C)
const {
1600 SValBuilder &SB =
C.getSValBuilder();
1602 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1603 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1604 AllocationFamily(AF_Malloc));
1605 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1606 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1607 C.addTransition(State);
1612 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1617 const CallEvent &
Call,
1618 CheckerContext &
C)
const {
1632 bool IsKnownToBeAllocated =
false;
1633 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1634 IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1637 C.addTransition(State);
1641 const CallEvent &
Call,
1642 CheckerContext &
C)
const {
1650 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1656 if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||
1657 SizeOpt->isUnknownOrUndef())
1660 const auto LinePtr = LinePtrOpt->getAs<DefinedSVal>();
1661 const auto Size = SizeOpt->getAs<DefinedSVal>();
1662 const MemRegion *LinePtrReg = LinePtr->getAsRegion();
1668 AllocationFamily(AF_Malloc), *LinePtr));
1672 CheckerContext &
C)
const {
1673 State = ReallocMemAux(
C,
Call,
false, State,
1674 AllocationFamily(AF_Malloc),
1676 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1677 State = ProcessZeroAllocCheck(
C,
Call, 2, State);
1678 C.addTransition(State);
1682 const CallEvent &
Call,
1683 CheckerContext &
C)
const {
1684 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1687 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1690 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1691 MismatchedDeallocatorChecker.isEnabled()) {
1696 switch (I->getOwnKind()) {
1697 case OwnershipAttr::Returns:
1698 State = MallocMemReturnsAttr(
C,
Call, I, State);
1700 case OwnershipAttr::Takes:
1701 case OwnershipAttr::Holds:
1702 State = FreeMemAttr(
C,
Call, I, State);
1707 C.addTransition(State);
1710bool MallocChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
1711 if (!
Call.getOriginExpr())
1716 if (
const CheckFn *Callback = FreeingMemFnMap.
lookup(
Call)) {
1717 (*Callback)(
this, State,
Call,
C);
1721 if (
const CheckFn *Callback = AllocatingMemFnMap.
lookup(
Call)) {
1722 State = MallocBindRetVal(
C,
Call, State,
false);
1723 (*Callback)(
this, State,
Call,
C);
1727 if (
const CheckFn *Callback = ReallocatingMemFnMap.
lookup(
Call)) {
1728 State = MallocBindRetVal(
C,
Call, State,
false);
1729 (*Callback)(
this, State,
Call,
C);
1734 State = MallocBindRetVal(
C,
Call, State,
false);
1735 checkCXXNewOrCXXDelete(State,
Call,
C);
1740 checkCXXNewOrCXXDelete(State,
Call,
C);
1744 if (
const CheckFn *Callback = AllocaMemFnMap.
lookup(
Call)) {
1745 State = MallocBindRetVal(
C,
Call, State,
true);
1746 (*Callback)(
this, State,
Call,
C);
1750 if (isFreeingOwnershipAttrCall(
Call) || isAllocatingOwnershipAttrCall(
Call)) {
1751 if (isAllocatingOwnershipAttrCall(
Call))
1752 State = MallocBindRetVal(
C,
Call, State,
false);
1753 checkOwnershipAttr(State,
Call,
C);
1762 CheckerContext &
C,
const CallEvent &
Call,
const unsigned IndexOfSizeArg,
1767 const Expr *Arg =
nullptr;
1769 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1770 Arg = CE->
getArg(IndexOfSizeArg);
1771 }
else if (
const CXXNewExpr *NE =
1772 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1773 if (
NE->isArray()) {
1774 Arg = *
NE->getArraySize();
1779 assert(
false &&
"not a CallExpr or CXXNewExpr");
1784 RetVal = State->getSVal(
Call.getOriginExpr(),
C.getStackFrame());
1789 State->getSVal(Arg,
Call.getStackFrame()).getAs<DefinedSVal>();
1796 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1800 std::tie(TrueState, FalseState) =
1801 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal,
Zero));
1803 if (TrueState && !FalseState) {
1804 SymbolRef Sym = RetVal->getAsLocSymbol();
1808 const RefState *RS = State->get<RegionState>(Sym);
1810 if (RS->isAllocated())
1811 return TrueState->set<RegionState>(
1812 Sym, RefState::getAllocatedOfSizeZero(RS));
1819 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1829 while (!PointeeType.isNull()) {
1831 PointeeType = PointeeType->getPointeeType();
1844 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1850 for (
const auto *CtorParam : CtorD->
parameters()) {
1853 if (CtorParamPointeeT.
isNull())
1866MallocChecker::processNewAllocation(
const CXXAllocatorCall &
Call,
1868 AllocationFamily Family)
const {
1872 const CXXNewExpr *
NE =
Call.getOriginExpr();
1873 const ParentMap &PM =
C.getStackFrame()->getParentMap();
1887 SVal
Target =
Call.getObjectUnderConstruction();
1888 if (
Call.getOriginExpr()->isArray()) {
1889 if (
auto SizeEx =
NE->getArraySize())
1890 checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1891 AllocationFamily(AF_CXXNewArray));
1895 State = ProcessZeroAllocCheck(
C,
Call, 0, State,
Target);
1899void MallocChecker::checkNewAllocator(
const CXXAllocatorCall &
Call,
1900 CheckerContext &
C)
const {
1901 if (!
C.wasInlined) {
1904 AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1906 C.addTransition(State);
1916 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1917 return FirstSlot ==
"dataWithBytesNoCopy" ||
1918 FirstSlot ==
"initWithBytesNoCopy" ||
1919 FirstSlot ==
"initWithCharactersNoCopy";
1926 for (
unsigned i = 1; i < S.
getNumArgs(); ++i)
1928 return !
Call.getArgSVal(i).isZeroConstant();
1930 return std::nullopt;
1933void MallocChecker::checkPostObjCMessage(
const ObjCMethodCall &
Call,
1934 CheckerContext &
C)
const {
1945 if (
Call.hasNonZeroCallbackArg())
1948 bool IsKnownToBeAllocatedMemory;
1950 true, IsKnownToBeAllocatedMemory,
1951 AllocationFamily(AF_Malloc),
1954 C.addTransition(State);
1958MallocChecker::MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
1959 const OwnershipAttr *Att,
1964 auto attrClassName = Att->getModule()->getName();
1965 auto Family = AllocationFamily(AF_Custom, attrClassName);
1967 if (!Att->args().empty()) {
1968 return MallocMemAux(
C,
Call,
1969 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1970 UnknownVal(), State, Family);
1972 return MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State, Family);
1976 const CallEvent &
Call,
1978 bool isAlloca)
const {
1979 const Expr *CE =
Call.getOriginExpr();
1985 unsigned Count =
C.blockCount();
1986 SValBuilder &SVB =
C.getSValBuilder();
1987 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
1988 DefinedSVal RetVal =
1992 return State->BindExpr(CE,
C.getStackFrame(), RetVal);
1996 const CallEvent &
Call,
1997 const Expr *SizeEx, SVal
Init,
1999 AllocationFamily Family)
const {
2004 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
2007void MallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRef State,
2009 llvm::ArrayRef<SymbolRef> TaintedSyms,
2010 AllocationFamily Family)
const {
2011 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State,
this)) {
2013 std::make_unique<PathSensitiveBugReport>(TaintedAllocChecker, Msg, N);
2014 for (
const auto *TaintedSym : TaintedSyms) {
2015 R->markInteresting(TaintedSym);
2017 C.emitReport(std::move(R));
2021void MallocChecker::checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
2023 AllocationFamily Family)
const {
2026 std::vector<SymbolRef> TaintedSyms =
2028 if (TaintedSyms.empty())
2031 SValBuilder &SVB =
C.getSValBuilder();
2037 const llvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
2039 SVB.
makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));
2040 std::optional<NonLoc> SizeNL = SizeSVal.
getAs<NonLoc>();
2041 auto Cmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
2042 .
getAs<DefinedOrUnknownSVal>();
2045 auto [StateTooLarge, StateNotTooLarge] = State->assume(*
Cmp);
2046 if (!StateTooLarge && StateNotTooLarge) {
2051 std::string
Callee =
"Memory allocation function";
2052 if (
Call.getCalleeIdentifier())
2053 Callee =
Call.getCalleeIdentifier()->getName().str();
2055 Callee +
" is called with a tainted (potentially attacker controlled) "
2056 "value. Make sure the value is bound checked.",
2057 State,
C, TaintedSyms, Family);
2061 const CallEvent &
Call, SVal Size,
2063 AllocationFamily Family)
const {
2067 const Expr *CE =
Call.getOriginExpr();
2072 "Allocation functions must return a pointer");
2074 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
2075 SVal RetVal = State->getSVal(CE,
C.getStackFrame());
2079 State = State->bindDefaultInitial(RetVal,
Init, SF);
2083 Size = UnknownVal();
2085 checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
2089 Size.castAs<DefinedOrUnknownSVal>());
2095MallocChecker::FailedAlloc(CheckerContext &
C,
const CallEvent &
Call,
2097 llvm::ArrayRef<unsigned> SizeArgIndexes)
const {
2098 if (!State || !ModelAllocationFailure)
2101 for (
unsigned SizeArgI : SizeArgIndexes) {
2102 auto DefArgVal =
Call.getArgSVal(SizeArgI).getAs<DefinedOrUnknownSVal>();
2105 State = State->assume(*DefArgVal,
true);
2110 auto RetVal = State->getSVal(
Call.getOriginExpr(),
C.getStackFrame())
2111 .castAs<DefinedOrUnknownSVal>();
2112 return State->assume(RetVal,
false);
2117 AllocationFamily Family,
2118 std::optional<SVal> RetVal) {
2124 RetVal = State->getSVal(E,
C.getStackFrame());
2127 if (!RetVal->getAs<
Loc>())
2130 SymbolRef Sym = RetVal->getAsLocSymbol();
2138 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
2144 const CallEvent &
Call,
2145 const OwnershipAttr *Att,
2150 auto attrClassName = Att->getModule()->getName();
2151 auto Family = AllocationFamily(AF_Custom, attrClassName);
2153 bool IsKnownToBeAllocated =
false;
2155 for (
const auto &Arg : Att->args()) {
2157 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
2158 Att->getOwnKind() == OwnershipAttr::Holds,
2159 IsKnownToBeAllocated, Family);
2167 const CallEvent &
Call,
2169 bool Hold,
bool &IsKnownToBeAllocated,
2170 AllocationFamily Family,
2171 bool ReturnsNullOnFailure)
const {
2175 if (
Call.getNumArgs() < (
Num + 1))
2178 return FreeMemAux(
C,
Call.getArgExpr(
Num),
Call, State, Hold,
2179 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2186 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
2188 assert(*Ret &&
"We should not store the null return symbol");
2191 RetStatusSymbol = *Ret;
2199 const CallExpr *CE = dyn_cast<CallExpr>(E);
2210 if (I->getOwnKind() != OwnershipAttr::Takes)
2213 os <<
", which takes ownership of '" << I->getModule()->getName() <<
'\'';
2219 if (
const CallExpr *CE = dyn_cast<CallExpr>(E)) {
2235 if (Msg->isInstanceMessage())
2239 Msg->getSelector().print(os);
2243 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
2262 switch (Family.Kind) {
2269 case AF_CXXNewArray:
2272 case AF_IfNameIndex:
2273 os <<
"'if_nameindex()'";
2275 case AF_InnerBuffer:
2276 os <<
"container-specific allocator";
2279 os << Family.CustomName.value();
2283 assert(
false &&
"not a deallocation expression");
2288 switch (Family.Kind) {
2295 case AF_CXXNewArray:
2298 case AF_IfNameIndex:
2299 os <<
"'if_freenameindex()'";
2301 case AF_InnerBuffer:
2302 os <<
"container-specific deallocator";
2305 os <<
"function that takes ownership of '" << Family.CustomName.value()
2310 assert(
false &&
"not a deallocation expression");
2315MallocChecker::FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
2317 bool Hold,
bool &IsKnownToBeAllocated,
2318 AllocationFamily Family,
bool ReturnsNullOnFailure,
2319 std::optional<SVal> ArgValOpt)
const {
2324 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2327 DefinedOrUnknownSVal location = ArgVal.
castAs<DefinedOrUnknownSVal>();
2335 std::tie(notNullState, nullState) = State->assume(location);
2336 if (nullState && !notNullState)
2345 const Expr *ParentExpr =
Call.getOriginExpr();
2364 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2365 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2370 R =
R->StripCasts();
2374 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2381 if (!
R->hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {
2390 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2396 const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(
R->getBaseRegion());
2403 const RefState *RsBase = State->get<RegionState>(SymBase);
2404 SymbolRef PreviousRetStatusSymbol =
nullptr;
2406 IsKnownToBeAllocated =
2407 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2412 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2418 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2420 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2421 SymBase, PreviousRetStatusSymbol);
2427 if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2428 RsBase->isEscaped()) {
2431 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2432 if (!DeallocMatchesAlloc) {
2434 RsBase, SymBase, Hold);
2440 RegionOffset Offset =
R->getAsOffset();
2444 const Expr *AllocExpr =
cast<Expr>(RsBase->getStmt());
2453 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2459 State = State->remove<FreeReturnValue>(SymBase);
2463 if (ReturnsNullOnFailure) {
2464 SVal RetVal =
C.getSVal(ParentExpr);
2466 if (RetStatusSymbol) {
2467 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2468 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2476 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2481 State = State->invalidateRegions({location},
Call.getCFGElementRef(),
2482 C.blockCount(),
C.getStackFrame(),
2488 return State->set<RegionState>(SymBase,
2489 RefState::getRelinquished(Family,
2492 return State->set<RegionState>(SymBase,
2493 RefState::getReleased(Family, ParentExpr));
2497const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family)
const {
2498 switch (Family.Kind) {
2502 case AF_IfNameIndex:
2503 return MallocChecker.getAs<T>();
2505 case AF_CXXNewArray: {
2506 const T *ND = NewDeleteChecker.getAs<T>();
2507 const T *NDL = NewDeleteLeaksChecker.getAs<T>();
2510 if constexpr (std::is_same_v<T, CheckerFrontend>) {
2511 assert(ND && NDL &&
"Casting to CheckerFrontend always succeeds");
2513 return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;
2515 assert(!(ND && NDL) &&
2516 "NewDelete and NewDeleteLeaks must not share a bug type");
2517 return ND ? ND : NDL;
2519 case AF_InnerBuffer:
2520 return InnerPointerChecker.getAs<T>();
2522 assert(
false &&
"no family");
2525 assert(
false &&
"unhandled family");
2529const T *MallocChecker::getRelevantFrontendAs(CheckerContext &
C,
2531 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2532 return MallocChecker.getAs<T>();
2534 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2536 return getRelevantFrontendAs<T>(RS->getAllocationFamily());
2539bool MallocChecker::SummarizeValue(raw_ostream &os, SVal
V) {
2540 if (std::optional<nonloc::ConcreteInt> IntVal =
2541 V.getAs<nonloc::ConcreteInt>())
2542 os <<
"an integer (" << IntVal->getValue() <<
")";
2543 else if (std::optional<loc::ConcreteInt> ConstAddr =
2544 V.getAs<loc::ConcreteInt>())
2545 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2546 else if (std::optional<loc::GotoLabel> Label =
V.getAs<loc::GotoLabel>())
2547 os <<
"the address of the label '" << Label->getLabel()->getName() <<
"'";
2554bool MallocChecker::SummarizeRegion(
ProgramStateRef State, raw_ostream &os,
2555 const MemRegion *MR) {
2557 case MemRegion::FunctionCodeRegionKind: {
2560 os <<
"the address of the function '" << *FD <<
'\'';
2562 os <<
"the address of a function";
2565 case MemRegion::BlockCodeRegionKind:
2568 case MemRegion::BlockDataRegionKind:
2576 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2584 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2586 os <<
"the address of a local stack variable";
2591 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2599 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2601 os <<
"the address of a parameter";
2606 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2615 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2617 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2619 os <<
"the address of a global variable";
2628void MallocChecker::HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal,
2630 const Expr *DeallocExpr,
2631 AllocationFamily Family)
const {
2632 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2635 if (!Frontend->isEnabled()) {
2640 if (ExplodedNode *N =
C.generateErrorNode()) {
2641 SmallString<100> buf;
2642 llvm::raw_svector_ostream os(buf);
2645 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2646 MR = ER->getSuperRegion();
2648 os <<
"Argument to ";
2650 os <<
"deallocator";
2654 MR ? SummarizeRegion(
C.getState(), os, MR) : SummarizeValue(os, ArgVal);
2656 os <<
", which is not memory allocated by ";
2658 os <<
"not memory allocated by ";
2662 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2664 R->markInteresting(MR);
2666 C.emitReport(std::move(R));
2670void MallocChecker::HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
2671 SourceRange Range)
const {
2672 const FreeAlloca *Frontend;
2674 if (MallocChecker.isEnabled())
2675 Frontend = &MallocChecker;
2676 else if (MismatchedDeallocatorChecker.isEnabled())
2677 Frontend = &MismatchedDeallocatorChecker;
2683 if (ExplodedNode *N =
C.generateErrorNode()) {
2684 auto R = std::make_unique<PathSensitiveBugReport>(
2685 Frontend->FreeAllocaBug,
2686 "Memory allocated by 'alloca()' should not be deallocated", N);
2689 C.emitReport(std::move(R));
2693void MallocChecker::HandleMismatchedDealloc(CheckerContext &
C,
2695 const Expr *DeallocExpr,
2697 bool OwnershipTransferred)
const {
2698 if (!MismatchedDeallocatorChecker.isEnabled()) {
2703 if (ExplodedNode *N =
C.generateErrorNode()) {
2704 SmallString<100> buf;
2705 llvm::raw_svector_ostream os(buf);
2707 const Expr *AllocExpr =
cast<Expr>(RS->getStmt());
2708 SmallString<20> AllocBuf;
2709 llvm::raw_svector_ostream AllocOs(AllocBuf);
2710 SmallString<20> DeallocBuf;
2711 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2713 if (OwnershipTransferred) {
2715 os << DeallocOs.str() <<
" cannot";
2719 os <<
" take ownership of memory";
2722 os <<
" allocated by " << AllocOs.str();
2726 os <<
" allocated by " << AllocOs.str();
2728 os <<
" should be deallocated by ";
2732 os <<
", not " << DeallocOs.str();
2737 auto R = std::make_unique<PathSensitiveBugReport>(
2738 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);
2739 R->markInteresting(Sym);
2741 R->addVisitor<MallocBugVisitor>(Sym);
2742 C.emitReport(std::move(R));
2746void MallocChecker::HandleOffsetFree(CheckerContext &
C, SVal ArgVal,
2747 SourceRange Range,
const Expr *DeallocExpr,
2748 AllocationFamily Family,
2749 const Expr *AllocExpr)
const {
2750 const OffsetFree *Frontend = getRelevantFrontendAs<OffsetFree>(Family);
2753 if (!Frontend->isEnabled()) {
2758 ExplodedNode *N =
C.generateErrorNode();
2762 SmallString<100> buf;
2763 llvm::raw_svector_ostream os(buf);
2764 SmallString<20> AllocNameBuf;
2765 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2768 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2774 "Only symbols with a valid offset can have offset free errors");
2776 int offsetBytes = Offset.
getOffset() /
C.getASTContext().getCharWidth();
2778 os <<
"Argument to ";
2780 os <<
"deallocator";
2781 os <<
" is offset by "
2784 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2785 <<
" from the start of ";
2787 os <<
"memory allocated by " << AllocNameOs.str();
2789 os <<
"allocated memory";
2791 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->OffsetFreeBug,
2795 C.emitReport(std::move(R));
2798void MallocChecker::HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
2800 const UseFree *Frontend = getRelevantFrontendAs<UseFree>(
C, Sym);
2803 if (!Frontend->isEnabled()) {
2808 if (ExplodedNode *N =
C.generateErrorNode()) {
2809 AllocationFamily AF =
2810 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2812 auto R = std::make_unique<PathSensitiveBugReport>(
2813 Frontend->UseFreeBug,
2814 AF.Kind == AF_InnerBuffer
2815 ?
"Inner pointer of container used after re/deallocation"
2816 :
"Use of memory after it is released",
2819 R->markInteresting(Sym);
2821 R->addVisitor<MallocBugVisitor>(Sym);
2823 if (AF.Kind == AF_InnerBuffer)
2826 C.emitReport(std::move(R));
2830void MallocChecker::HandleDoubleFree(CheckerContext &
C, SourceRange Range,
2833 const DoubleFree *Frontend = getRelevantFrontendAs<DoubleFree>(
C, Sym);
2836 if (!Frontend->isEnabled()) {
2841 if (ExplodedNode *N =
C.generateErrorNode()) {
2842 auto R = std::make_unique<PathSensitiveBugReport>(
2843 Frontend->DoubleFreeBug,
2844 (Released ?
"Attempt to release already released memory"
2845 :
"Attempt to release non-owned memory"),
2847 if (
Range.isValid())
2849 R->markInteresting(Sym);
2851 R->markInteresting(PrevSym);
2852 R->addVisitor<MallocBugVisitor>(Sym);
2853 C.emitReport(std::move(R));
2857void MallocChecker::HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
2859 const UseZeroAllocated *Frontend =
2860 getRelevantFrontendAs<UseZeroAllocated>(
C, Sym);
2863 if (!Frontend->isEnabled()) {
2868 if (ExplodedNode *N =
C.generateErrorNode()) {
2869 auto R = std::make_unique<PathSensitiveBugReport>(
2870 Frontend->UseZeroAllocatedBug,
"Use of memory allocated with size zero",
2875 R->markInteresting(Sym);
2876 R->addVisitor<MallocBugVisitor>(Sym);
2878 C.emitReport(std::move(R));
2882void MallocChecker::HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal,
2884 const Expr *FreeExpr,
2885 AllocationFamily Family)
const {
2886 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2889 if (!Frontend->isEnabled()) {
2894 if (ExplodedNode *N =
C.generateErrorNode()) {
2895 SmallString<100> Buf;
2896 llvm::raw_svector_ostream Os(Buf);
2899 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2900 MR = ER->getSuperRegion();
2902 Os <<
"Argument to ";
2904 Os <<
"deallocator";
2906 Os <<
" is a function pointer";
2908 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2910 R->markInteresting(MR);
2912 C.emitReport(std::move(R));
2917MallocChecker::ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
2919 AllocationFamily Family,
bool SuffixWithN)
const {
2928 const Expr *arg0Expr = CE->
getArg(0);
2929 SVal Arg0Val =
C.getSVal(arg0Expr);
2932 DefinedOrUnknownSVal arg0Val = Arg0Val.
castAs<DefinedOrUnknownSVal>();
2934 SValBuilder &svalBuilder =
C.getSValBuilder();
2936 DefinedOrUnknownSVal PtrEQ = svalBuilder.
evalEQ(
2937 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2940 const Expr *Arg1 = CE->
getArg(1);
2943 SVal TotalSize =
C.getSVal(Arg1);
2945 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2950 DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(
2951 State, TotalSize.
castAs<DefinedOrUnknownSVal>(),
2952 svalBuilder.makeIntValWithWidth(
2953 svalBuilder.getContext().getCanonicalSizeType(), 0));
2956 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2958 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2961 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2962 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2966 if (PrtIsNull && !SizeIsZero) {
2968 C,
Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
2973 if (PrtIsNull && SizeIsZero)
2978 bool IsKnownToBeAllocated =
false;
2987 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2992 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2995 MallocMemAux(
C,
Call, TotalSize, UnknownVal(), stateFree, Family);
2999 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
3000 if (ShouldFreeOnFail)
3001 Kind = OAR_FreeOnFailure;
3002 else if (!IsKnownToBeAllocated)
3003 Kind = OAR_DoNotTrackAfterFailure;
3007 SVal RetVal = stateRealloc->getSVal(CE,
C.getStackFrame());
3009 assert(FromPtr && ToPtr &&
3010 "By this point, FreeMemAux and MallocMemAux should have checked "
3011 "whether the argument or the return value is symbolic!");
3015 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
3016 ReallocPair(FromPtr, Kind));
3018 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
3019 return stateRealloc;
3025 const CallEvent &
Call,
3030 if (
Call.getNumArgs() < 2)
3033 SValBuilder &svalBuilder =
C.getSValBuilder();
3036 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
3038 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State,
3039 AllocationFamily(AF_Malloc));
3042MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
3044 CheckerContext &
C) {
3048 const ExplodedNode *AllocNode = N;
3049 const MemRegion *ReferenceRegion =
nullptr;
3053 if (!State->get<RegionState>(Sym))
3058 if (!ReferenceRegion) {
3059 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
3060 SVal Val = State->getSVal(MR);
3066 ReferenceRegion = MR;
3074 if (NSF == LeakStackFrame || NSF->
isParentOf(LeakStackFrame))
3079 return LeakInfo(AllocNode, ReferenceRegion);
3082void MallocChecker::HandleLeak(
SymbolRef Sym, ExplodedNode *N,
3083 CheckerContext &
C)
const {
3084 assert(N &&
"HandleLeak is only called with a non-null node");
3086 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3087 assert(RS &&
"cannot leak an untracked symbol");
3088 AllocationFamily Family = RS->getAllocationFamily();
3090 if (Family.Kind == AF_Alloca)
3093 const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);
3097 if (!Frontend || !Frontend->isEnabled())
3103 PathDiagnosticLocation LocUsedForUniqueing;
3104 const ExplodedNode *AllocNode =
nullptr;
3105 const MemRegion *Region =
nullptr;
3106 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
3111 AllocationStmt,
C.getSourceManager(), AllocNode->
getStackFrame());
3113 SmallString<200> buf;
3114 llvm::raw_svector_ostream os(buf);
3116 os <<
"Potential leak of memory pointed to by ";
3119 os <<
"Potential memory leak";
3122 auto R = std::make_unique<PathSensitiveBugReport>(
3123 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3125 R->markInteresting(Sym);
3126 R->addVisitor<MallocBugVisitor>(Sym,
true);
3127 if (ShouldRegisterNoOwnershipChangeVisitor)
3128 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
3129 C.emitReport(std::move(R));
3132void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3133 CheckerContext &
C)
const
3136 RegionStateTy OldRS = state->get<RegionState>();
3137 RegionStateTy::Factory &F = state->get_context<RegionState>();
3139 RegionStateTy RS = OldRS;
3140 SmallVector<SymbolRef, 2> Errors;
3141 for (
auto [Sym, State] : RS) {
3142 if (SymReaper.
isDead(Sym)) {
3143 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3144 Errors.push_back(Sym);
3146 RS = F.remove(RS, Sym);
3152 assert(state->get<ReallocPairs>() ==
3153 C.getState()->get<ReallocPairs>());
3154 assert(state->get<FreeReturnValue>() ==
3155 C.getState()->get<FreeReturnValue>());
3160 ReallocPairsTy RP = state->get<ReallocPairs>();
3161 for (
auto [Sym, ReallocPair] : RP) {
3162 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
3163 state = state->remove<ReallocPairs>(Sym);
3168 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3169 for (
auto [Sym, RetSym] : FR) {
3170 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
3171 state = state->remove<FreeReturnValue>(Sym);
3176 ExplodedNode *N =
C.getPredecessor();
3177 if (!Errors.empty()) {
3178 N =
C.generateNonFatalErrorNode(
C.getState());
3181 HandleLeak(Sym, N,
C);
3186 C.addTransition(state->set<RegionState>(RS), N);
3193 return Name ==
"unique_ptr" || Name ==
"shared_ptr";
3200 if (
const auto *TST = QT->
getAs<TemplateSpecializationType>()) {
3201 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
3224 llvm::SmallPtrSetImpl<const MemRegion *> *
Out;
3227 llvm::SmallPtrSetImpl<const MemRegion *> &
Out)
3240 C->getState()->getLValue(BaseDecl,
Reg->getAs<
SubRegion>(), IsVirtual);
3245 return std::nullopt;
3261 std::optional<FieldConsumer> FC = std::nullopt) {
3274 BaseSpec.getType()->getAsCXXRecordDecl()) {
3275 std::optional<FieldConsumer> NewFC;
3277 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());
3295 if (!T->isRecordType() || T->isReferenceType())
3327 const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(
Call.getDecl());
3331 const auto *RD = CD->getParent();
3336 for (
const auto *Param : CD->parameters()) {
3337 QualType ParamType = Param->getType();
3352 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {
3369 for (
unsigned I = 0, E = std::min(
Call.getNumArgs(), CD->getNumParams());
3371 const Expr *ArgExpr =
Call.getArgExpr(I);
3375 QualType ParamType = CD->getParamDecl(I)->
getType();
3379 SVal ArgVal =
Call.getArgSVal(I);
3381 if (Sym && State->contains<RegionState>(Sym)) {
3382 const RefState *RS = State->get<RegionState>(Sym);
3383 if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {
3384 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3400 return handleSmartPointerConstructorArguments(
Call, State);
3404 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;
3405 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3406 const Expr *AE =
Call.getArgExpr(I);
3415 SVal ArgVal =
Call.getArgSVal(I);
3416 const MemRegion *ArgRegion = ArgVal.
getAsRegion();
3419 SmartPtrFieldRoots);
3423 if (!SmartPtrFieldRoots.empty()) {
3424 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(
3425 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());
3426 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(
3427 SmartPtrFieldRootsVec, State);
3433void MallocChecker::checkPostCall(
const CallEvent &
Call,
3434 CheckerContext &
C)
const {
3436 if (
const auto *PostFN = PostFnMap.
lookup(
Call)) {
3437 (*PostFN)(
this,
C.getState(),
Call,
C);
3442 C.addTransition(handleSmartPointerRelatedCalls(
Call,
C,
C.getState()));
3445void MallocChecker::checkPreCall(
const CallEvent &
Call,
3446 CheckerContext &
C)
const {
3448 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3449 const CXXDeleteExpr *DE = DC->getOriginExpr();
3455 if (!NewDeleteChecker.isEnabled())
3463 bool IsKnownToBeAllocated;
3466 false, IsKnownToBeAllocated,
3467 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3469 C.addTransition(State);
3480 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3481 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3485 HandleDoubleFree(
C, SourceRange(),
true, Sym,
3493 if (
const auto *PreFN = PreFnMap.
lookup(
Call)) {
3494 (*PreFN)(
this,
C.getState(),
Call,
C);
3502 if (
const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&
Call)) {
3503 const FunctionDecl *FD = FC->getDecl();
3510 if (MallocChecker.isEnabled() && isFreeingCall(
Call))
3515 if (
const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&
Call)) {
3516 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3517 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3522 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3523 SVal ArgSVal =
Call.getArgSVal(I);
3528 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3534void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3535 CheckerContext &
C)
const {
3536 checkEscapeOnReturn(S,
C);
3542void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3543 CheckerContext &
C)
const {
3544 checkEscapeOnReturn(S,
C);
3547void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3548 CheckerContext &
C)
const {
3558 SVal RetVal =
C.getSVal(E);
3565 if (
const SymbolicRegion *BMR =
3567 Sym = BMR->getSymbol();
3571 checkUseAfterFree(Sym,
C, E);
3577void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3578 CheckerContext &
C)
const {
3586 const BlockDataRegion *
R =
3589 auto ReferencedVars =
R->referenced_vars();
3590 if (ReferencedVars.empty())
3593 SmallVector<const MemRegion *, 10> Regions;
3594 MemRegionManager &MemMgr =
C.getSValBuilder().getRegionManager();
3596 for (
const auto &Var : ReferencedVars) {
3597 const VarRegion *VR = Var.getCapturedRegion();
3601 Regions.push_back(VR);
3605 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3606 C.addTransition(state);
3611 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3612 return (RS && RS->isReleased());
3615bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3616 const CallEvent &
Call, CheckerContext &
C)
const {
3617 if (
Call.getNumArgs() == 0)
3620 StringRef FunctionStr =
"";
3621 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3622 if (
const Stmt *Body = FD->
getBody())
3623 if (Body->getBeginLoc().isValid())
3627 C.getSourceManager(),
C.getLangOpts());
3630 if (!FunctionStr.contains(
"__isl_"))
3636 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3637 if (
const RefState *RS = State->get<RegionState>(Sym))
3638 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3640 C.addTransition(State);
3644bool MallocChecker::checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
3645 const Stmt *S)
const {
3655void MallocChecker::checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
3656 const Stmt *S)
const {
3659 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3660 if (RS->isAllocatedOfSizeZero())
3661 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3663 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3669void MallocChecker::checkLocation(SVal l,
bool isLoad,
const Stmt *S,
3670 CheckerContext &
C)
const {
3673 checkUseAfterFree(Sym,
C, S);
3674 checkUseZeroAllocated(Sym,
C, S);
3682 bool Assumption)
const {
3683 RegionStateTy RS = state->get<RegionState>();
3684 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3686 ConstraintManager &CMgr = state->getConstraintManager();
3687 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3689 state = state->remove<RegionState>(Sym);
3694 ReallocPairsTy RP = state->get<ReallocPairs>();
3695 for (
auto [Sym, ReallocPair] : RP) {
3697 ConstraintManager &CMgr = state->getConstraintManager();
3698 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3702 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3703 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3704 if (RS->isReleased()) {
3705 switch (ReallocPair.Kind) {
3706 case OAR_ToBeFreedAfterFailure:
3707 state = state->set<RegionState>(ReallocSym,
3708 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3710 case OAR_DoNotTrackAfterFailure:
3711 state = state->remove<RegionState>(ReallocSym);
3714 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3718 state = state->remove<ReallocPairs>(Sym);
3724bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3725 const CallEvent *
Call,
3729 EscapingSymbol =
nullptr;
3739 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(
Call)) {
3742 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3755 return *FreeWhenDone;
3761 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3762 if (FirstSlot.ends_with(
"NoCopy"))
3769 if (FirstSlot.starts_with(
"addPointer") ||
3770 FirstSlot.starts_with(
"insertPointer") ||
3771 FirstSlot.starts_with(
"replacePointer") ||
3772 FirstSlot ==
"valueWithPointer") {
3779 if (Msg->getMethodFamily() ==
OMF_init) {
3780 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3796 if (isMemCall(*
Call))
3800 if (!
Call->isInSystemHeader())
3807 StringRef FName = II->
getName();
3811 if (FName.ends_with(
"NoCopy")) {
3815 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3816 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3817 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3818 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3819 if (DeallocatorName ==
"kCFAllocatorNull")
3830 if (FName ==
"funopen")
3831 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3837 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3838 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3839 if (
Call->getNumArgs() >= 1) {
3841 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3842 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3843 if (D->getCanonicalDecl()->getName().contains(
"std"))
3853 if (FName ==
"CGBitmapContextCreate" ||
3854 FName ==
"CGBitmapContextCreateWithData" ||
3855 FName ==
"CVPixelBufferCreateWithBytes" ||
3856 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3857 FName ==
"OSAtomicEnqueue") {
3861 if (FName ==
"postEvent" &&
3866 if (FName ==
"connectImpl" &&
3871 if (FName ==
"singleShotImpl" &&
3881 if (FName ==
"GetOwnedMessageInternal") {
3889 if (
Call->argumentsMayEscape())
3899 const CallEvent *
Call,
3901 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3907 const CallEvent *
Call,
3910 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3915 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3916 RS->getAllocationFamily().Kind == AF_CXXNew);
3922 bool IsConstPointerEscape)
const {
3927 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3934 if (EscapingSymbol && EscapingSymbol != sym)
3937 if (
const RefState *RS = State->get<RegionState>(sym))
3938 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3940 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3945bool MallocChecker::isArgZERO_SIZE_PTR(
ProgramStateRef State, CheckerContext &
C,
3946 SVal ArgVal)
const {
3947 if (!KernelZeroSizePtrValue)
3948 KernelZeroSizePtrValue =
3951 const llvm::APSInt *ArgValKnown =
3952 C.getSValBuilder().getKnownValue(State, ArgVal);
3953 return ArgValKnown && *KernelZeroSizePtrValue &&
3954 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3959 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3960 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3962 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3964 if (!currMap.lookup(sym))
3974 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3975 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3976 N.contains_insensitive(
"intrusive") ||
3977 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3986 BugReporterContext &BRC,
3987 PathSensitiveBugReport &BR) {
3991 const RefState *RSCurr = state->get<RegionState>(Sym);
3992 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3997 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
4010 if (ReleaseFunctionSF && (ReleaseFunctionSF == CurrentSF ||
4012 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
4015 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
4016 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
4022 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
4025 if (
const auto *MD =
4027 const CXXRecordDecl *RD = MD->getParent();
4045 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
4046 SmallString<256> Buf;
4047 llvm::raw_svector_ostream
OS(Buf);
4050 if (isAllocated(RSCurr, RSPrev, S)) {
4051 Msg =
"Memory is allocated";
4052 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4053 Sym,
"Returned allocated memory");
4055 const auto Family = RSCurr->getAllocationFamily();
4056 switch (Family.Kind) {
4061 case AF_CXXNewArray:
4062 case AF_IfNameIndex:
4063 Msg =
"Memory is released";
4064 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4065 Sym,
"Returning; memory was released");
4067 case AF_InnerBuffer: {
4068 const MemRegion *ObjRegion =
4071 QualType ObjTy = TypedRegion->getValueType();
4072 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
4075 OS <<
"deallocated by call to destructor";
4076 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4077 Sym,
"Returning; inner buffer was deallocated");
4079 OS <<
"reallocated by call to '";
4080 const Stmt *S = RSCurr->getStmt();
4081 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
4082 OS << MemCallE->getMethodDecl()->getDeclName();
4083 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
4084 OS << OpCallE->getDirectCallee()->getDeclName();
4085 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
4087 CallEventRef<>
Call =
4089 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
4090 OS << D->getDeclName();
4095 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4096 Sym,
"Returning; inner buffer was reallocated");
4102 assert(
false &&
"Unhandled allocation family!");
4112 ReleaseFunctionSF = CurrentSF;
4115 for (
const StackFrame *SF = CurrentSF; SF; SF = SF->
getParent()) {
4116 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(SF->
getDecl())) {
4152 ReleaseFunctionSF = SF;
4156 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
4157 Msg =
"Memory ownership is transferred";
4158 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
4159 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
4160 Mode = ReallocationFailed;
4161 Msg =
"Reallocation failed";
4162 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
4163 Sym,
"Reallocation failed");
4167 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
4168 "We only support one failed realloc at a time.");
4170 FailedReallocSymbol = sym;
4175 }
else if (Mode == ReallocationFailed) {
4176 assert(FailedReallocSymbol &&
"No symbol to look for.");
4179 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
4181 Msg =
"Attempt to reallocate memory";
4182 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4183 Sym,
"Returned reallocated memory");
4184 FailedReallocSymbol =
nullptr;
4197 PathDiagnosticLocation Pos;
4199 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
4203 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
4209 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
4214void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
4215 const char *NL,
const char *Sep)
const {
4217 RegionStateTy RS = State->get<RegionState>();
4219 if (!RS.isEmpty()) {
4220 Out << Sep <<
"MallocChecker :" << NL;
4221 for (
auto [Sym,
Data] : RS) {
4222 const RefState *RefS = State->get<RegionState>(Sym);
4223 AllocationFamily Family = RefS->getAllocationFamily();
4225 const CheckerFrontend *Frontend =
4226 getRelevantFrontendAs<CheckerFrontend>(Family);
4240namespace allocation_state {
4244 AllocationFamily Family(AF_InnerBuffer);
4245 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
4255 Mgr.
getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);
4263 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
4265 Chk->ShouldRegisterNoOwnershipChangeVisitor =
4267 DMMName,
"AddNoOwnershipChangeNotes");
4268 Chk->ModelAllocationFailure =
4270 DMMName,
"ModelAllocationFailure");
4273bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
4277#define REGISTER_CHECKER(NAME) \
4278 void ento::register##NAME(CheckerManager &Mgr) { \
4279 Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr); \
4282 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
4291#undef REGISTER_CHECKER
#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.
Result
Implement __builtin_bit_cast and related operations.
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)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
CanQualType getCanonicalSizeType() const
CanQualType UnsignedLongTy
static bool hasSameType(QualType T1, QualType T2)
Determine whether the given types T1 and T2 are equivalent.
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.
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.
bool isParentOf(const StackFrame *SF) const
const Decl * getDecl() const
const StackFrame * getParent() const
It might return null.
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)
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.
const T * lookup(const CallEvent &Call) const
CallEventRef getSimpleCall(const CallExpr *E, ProgramStateRef State, const StackFrame *SF, 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.
ExplodedNode * getFirstPred()
const StackFrame * getStackFrame() const
static bool isLocType(QualType T)
const VarRegion * getVarRegion(const VarDecl *VD, const StackFrame *SF)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and StackFram...
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 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
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)
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const StackFrame *SF, unsigned Count)
Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...
DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const StackFrame *SF, QualType type, unsigned Count)
Conjure a symbol representing heap allocated memory region.
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
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 StackFrame * 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 Expr *E, const StackFrame *SF, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given expression 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 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