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;
411 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
414 DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
416 DynMemFrontend<Leak> NewDeleteLeaksChecker;
417 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
418 DynMemFrontend<UseFree> InnerPointerChecker;
421 CheckerFrontendWithBugType TaintedAllocChecker{
"Tainted Memory Allocation",
424 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
426 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
427 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
428 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
431 handleSmartPointerConstructorArguments(
const CallEvent &
Call,
436 void checkNewAllocator(
const CXXAllocatorCall &
Call, CheckerContext &
C)
const;
437 void checkPostObjCMessage(
const ObjCMethodCall &
Call, CheckerContext &
C)
const;
438 void checkPostStmt(
const BlockExpr *BE, CheckerContext &
C)
const;
439 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &
C)
const;
440 void checkPreStmt(
const ReturnStmt *S, CheckerContext &
C)
const;
441 void checkEndFunction(
const ReturnStmt *S, CheckerContext &
C)
const;
443 bool Assumption)
const;
444 void checkLocation(SVal l,
bool isLoad,
const Stmt *S,
445 CheckerContext &
C)
const;
449 const CallEvent *
Call,
453 const CallEvent *
Call,
457 const char *NL,
const char *Sep)
const override;
459 StringRef getDebugTag()
const override {
return "MallocChecker"; }
462#define CHECK_FN(NAME) \
463 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
494 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},
495 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},
498 const CallDescriptionMap<CheckFn> PostFnMap{
501 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},
502 {{CDM::CLibrary, {
"getdelim"}, 4},
503 &MallocChecker::checkGetDelimOrGetLine},
506 const CallDescriptionMap<CheckFn> FreeingMemFnMap{
507 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
508 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
509 &MallocChecker::checkIfFreeNameIndex},
510 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
511 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
514 bool isFreeingCall(
const CallEvent &
Call)
const;
515 static bool isFreeingOwnershipAttrCall(
const FunctionDecl *
Func);
516 static bool isFreeingOwnershipAttrCall(
const CallEvent &
Call);
517 static bool isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func);
518 static bool isAllocatingOwnershipAttrCall(
const CallEvent &
Call);
520 friend class NoMemOwnershipChangeVisitor;
522 CallDescriptionMap<CheckFn> AllocaMemFnMap{
523 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
524 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
528 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
529 &MallocChecker::checkAlloca},
532 CallDescriptionMap<CheckFn> AllocatingMemFnMap{
533 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
534 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
535 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
536 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
537 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
538 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
539 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
540 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
541 {{CDM::CLibrary, {
"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
542 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
543 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
544 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
545 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
546 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
547 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
548 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
549 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
550 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
551 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
552 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
555 CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
556 {{CDM::CLibrary, {
"realloc"}, 2},
557 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
558 {{CDM::CLibrary, {
"reallocf"}, 2},
559 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
true)},
560 {{CDM::CLibrary, {
"g_realloc"}, 2},
561 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
562 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
563 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
564 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
565 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
568 bool isMemCall(
const CallEvent &
Call)
const;
569 bool hasOwnershipReturns(
const CallEvent &
Call)
const;
570 bool hasOwnershipTakesHolds(
const CallEvent &
Call)
const;
571 void reportTaintBug(StringRef Msg,
ProgramStateRef State, CheckerContext &
C,
572 llvm::ArrayRef<SymbolRef> TaintedSyms,
573 AllocationFamily Family)
const;
575 void checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
577 AllocationFamily Family)
const;
580 mutable std::optional<uint64_t> KernelZeroFlagVal;
582 using KernelZeroSizePtrValueTy = std::optional<int>;
587 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
592 processNewAllocation(
const CXXAllocatorCall &
Call, CheckerContext &
C,
593 AllocationFamily Family)
const;
604 ProcessZeroAllocCheck(CheckerContext &
C,
const CallEvent &
Call,
606 std::optional<SVal> RetVal = std::nullopt);
625 MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
635 const CallEvent &
Call,
637 bool isAlloca)
const;
649 MallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
const Expr *SizeEx,
662 const CallEvent &
Call, SVal Size,
664 AllocationFamily Family)
const;
668 [[nodiscard]] std::optional<ProgramStateRef>
669 performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
690 const CallEvent &
Call,
691 const OwnershipAttr *Att,
715 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
716 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
740 FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
const CallEvent &
Call,
742 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
743 std::optional<SVal> ArgValOpt = {})
const;
759 ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
bool ShouldFreeOnFail,
761 bool SuffixWithN =
false)
const;
768 [[nodiscard]]
static SVal evalMulForBufferSize(CheckerContext &
C,
770 const Expr *BlockBytes);
778 const CallEvent &
Call,
783 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
784 CheckerContext &
C)
const;
787 bool checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
const Stmt *S)
const;
791 void checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
792 const Stmt *S)
const;
804 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
813 bool IsConstPointerEscape)
const;
816 void checkEscapeOnReturn(
const ReturnStmt *S, CheckerContext &
C)
const;
825 const T *getRelevantFrontendAs(AllocationFamily Family)
const;
828 const T *getRelevantFrontendAs(CheckerContext &
C,
SymbolRef Sym)
const;
830 static bool SummarizeValue(raw_ostream &os, SVal
V);
832 const MemRegion *MR);
834 void HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal, SourceRange Range,
835 const Expr *DeallocExpr,
836 AllocationFamily Family)
const;
838 void HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
839 SourceRange Range)
const;
841 void HandleMismatchedDealloc(CheckerContext &
C, SourceRange Range,
842 const Expr *DeallocExpr,
const RefState *RS,
843 SymbolRef Sym,
bool OwnershipTransferred)
const;
845 void HandleOffsetFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
846 const Expr *DeallocExpr, AllocationFamily Family,
847 const Expr *AllocExpr =
nullptr)
const;
849 void HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
852 void HandleDoubleFree(CheckerContext &
C, SourceRange Range,
bool Released,
855 void HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
858 void HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
859 const Expr *FreeExpr,
860 AllocationFamily Family)
const;
864 static LeakInfo getAllocationSite(
const ExplodedNode *N,
SymbolRef Sym,
867 void HandleLeak(
SymbolRef Sym, ExplodedNode *N, CheckerContext &
C)
const;
880class NoMemOwnershipChangeVisitor final :
public NoOwnershipChangeVisitor {
889 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
890 const auto *MallocChk =
static_cast<const MallocChecker *
>(&Checker);
891 if (MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
892 MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
895 if (
const auto *
Func =
896 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
897 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
904 return CallEnterState->get<RegionState>(Sym) !=
905 CallExitEndState->get<RegionState>(Sym);
912 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
913 ASTContext &ACtx)
final {
914 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
924 using namespace clang::ast_matchers;
929 for (BoundNodes
Match : Matches) {
930 if (
Match.getNodeAs<CXXDeleteExpr>(
"delete"))
933 if (
const auto *
Call =
Match.getNodeAs<CallExpr>(
"call"))
934 if (isFreeingCallAsWritten(*
Call))
946 N->getState()->getStateManager().getContext().getSourceManager());
947 return std::make_shared<PathDiagnosticEventPiece>(
948 L,
"Returning without deallocating memory or storing the pointer for "
949 "later deallocation");
953 NoMemOwnershipChangeVisitor(
SymbolRef Sym,
const MallocChecker *Checker)
954 : NoOwnershipChangeVisitor(Sym, Checker) {}
956 void Profile(llvm::FoldingSetNodeID &ID)
const override {
975 enum NotificationMode { Normal, ReallocationFailed };
981 NotificationMode Mode;
988 const StackFrame *ReleaseFunctionSF;
993 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
994 : Sym(S), Mode(Normal), FailedReallocSymbol(
nullptr),
995 ReleaseFunctionSF(
nullptr), IsLeak(isLeak) {}
997 static void *getTag() {
1002 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1003 ID.AddPointer(getTag());
1008 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
1010 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
1012 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1014 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1019 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
1022 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
1023 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
1024 (!Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
1029 static inline bool isRelinquished(
const RefState *RSCurr,
1030 const RefState *RSPrev,
const Stmt *Stmt) {
1032 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
1033 (RSCurr && RSCurr->isRelinquished()) &&
1034 (!RSPrev || !RSPrev->isRelinquished()));
1041 static inline bool hasReallocFailed(
const RefState *RSCurr,
1042 const RefState *RSPrev,
1044 return ((!isa_and_nonnull<CallExpr>(Stmt)) &&
1046 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1048 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1052 BugReporterContext &BRC,
1053 PathSensitiveBugReport &BR)
override;
1056 const ExplodedNode *EndPathNode,
1057 PathSensitiveBugReport &BR)
override {
1063 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1068 class StackHintGeneratorForReallocationFailed
1069 :
public StackHintGeneratorForSymbol {
1071 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1072 : StackHintGeneratorForSymbol(S, M) {}
1074 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1078 SmallString<200> buf;
1079 llvm::raw_svector_ostream os(buf);
1081 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1082 <<
" parameter failed";
1084 return std::string(os.str());
1087 std::string getMessageForReturn(
const CallExpr *CallExpr)
override {
1088 return "Reallocation of returned value failed";
1106 bool VisitSymbol(
SymbolRef sym)
override {
1107 state = state->remove<RegionState>(sym);
1127 explicit EscapeTrackedCallback(
ProgramStateRef S) : State(std::move(S)) {}
1130 bool VisitSymbol(
SymbolRef Sym)
override {
1131 if (
const RefState *RS = State->get<RegionState>(Sym)) {
1132 if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) {
1133 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
1141 EscapeTrackedRegionsReachableFrom(ArrayRef<const MemRegion *> Roots,
1148 SmallVector<const MemRegion *, 10> Regions;
1149 EscapeTrackedCallback Visitor(State);
1150 for (
const MemRegion *R : Roots) {
1151 Regions.push_back(R);
1153 State->scanReachableSymbols(Regions, Visitor);
1154 return Visitor.State;
1157 friend class SymbolVisitor;
1166 if (Kind != OO_New && Kind != OO_Array_New)
1182 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1193 return L.
isInvalid() || (!HasBody &&
SM.isInSystemHeader(L));
1200bool MallocChecker::isFreeingOwnershipAttrCall(
const CallEvent &
Call) {
1201 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1203 return Func && isFreeingOwnershipAttrCall(
Func);
1206bool MallocChecker::isFreeingOwnershipAttrCall(
const FunctionDecl *
Func) {
1207 if (
Func->hasAttrs()) {
1208 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1209 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1210 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1217bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1218 if (FreeingMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1221 return isFreeingOwnershipAttrCall(
Call);
1224bool MallocChecker::isAllocatingOwnershipAttrCall(
const CallEvent &
Call) {
1225 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1227 return Func && isAllocatingOwnershipAttrCall(
Func);
1230bool MallocChecker::isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func) {
1231 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1232 if (I->getOwnKind() == OwnershipAttr::Returns)
1239bool MallocChecker::isMemCall(
const CallEvent &
Call)
const {
1240 if (FreeingMemFnMap.lookup(
Call) || AllocatingMemFnMap.lookup(
Call) ||
1241 AllocaMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1244 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1247 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1248 return Func &&
Func->hasAttr<OwnershipAttr>();
1251std::optional<ProgramStateRef>
1252MallocChecker::performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
1270 ASTContext &Ctx =
C.getASTContext();
1273 if (!KernelZeroFlagVal) {
1275 case llvm::Triple::FreeBSD:
1276 KernelZeroFlagVal = 0x0100;
1278 case llvm::Triple::NetBSD:
1279 KernelZeroFlagVal = 0x0002;
1281 case llvm::Triple::OpenBSD:
1282 KernelZeroFlagVal = 0x0008;
1284 case llvm::Triple::Linux:
1286 KernelZeroFlagVal = 0x8000;
1294 return std::nullopt;
1301 if (
Call.getNumArgs() < 2)
1302 return std::nullopt;
1304 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1305 const SVal
V =
C.getSVal(FlagsEx);
1309 return std::nullopt;
1312 NonLoc Flags =
V.castAs<NonLoc>();
1313 NonLoc ZeroFlag =
C.getSValBuilder()
1314 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1316 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1319 if (MaskedFlagsUC.isUnknownOrUndef())
1320 return std::nullopt;
1321 DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
1325 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1328 if (TrueState && !FalseState) {
1329 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1330 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1331 AllocationFamily(AF_Malloc));
1334 return std::nullopt;
1337SVal MallocChecker::evalMulForBufferSize(CheckerContext &
C,
const Expr *Blocks,
1338 const Expr *BlockBytes) {
1339 SValBuilder &SB =
C.getSValBuilder();
1340 SVal BlocksVal =
C.getSVal(Blocks);
1341 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1343 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1349 const CallEvent &
Call,
1350 CheckerContext &
C)
const {
1351 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1352 AllocationFamily(AF_Malloc));
1353 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1354 C.addTransition(State);
1358 const CallEvent &
Call,
1359 CheckerContext &
C)
const {
1360 std::optional<ProgramStateRef> MaybeState =
1361 performKernelMalloc(
Call,
C, State);
1363 State = *MaybeState;
1365 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1366 AllocationFamily(AF_Malloc));
1367 C.addTransition(State);
1391 bool ShouldFreeOnFail)
const {
1400 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1401 AllocationFamily(AF_Malloc));
1402 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1403 C.addTransition(State);
1407 CheckerContext &
C)
const {
1408 State = CallocMem(
C,
Call, State);
1409 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1410 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1411 C.addTransition(State);
1415 CheckerContext &
C)
const {
1416 bool IsKnownToBeAllocatedMemory =
false;
1417 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1419 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1420 AllocationFamily(AF_Malloc));
1421 C.addTransition(State);
1425 CheckerContext &
C)
const {
1426 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1427 AllocationFamily(AF_Alloca));
1428 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1429 C.addTransition(State);
1433 CheckerContext &
C)
const {
1434 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1437 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1438 AllocationFamily(AF_Malloc));
1440 C.addTransition(State);
1444 const CallEvent &
Call,
1445 CheckerContext &
C)
const {
1448 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1449 AllocationFamily(AF_IfNameIndex));
1451 C.addTransition(State);
1455 const CallEvent &
Call,
1456 CheckerContext &
C)
const {
1457 bool IsKnownToBeAllocatedMemory =
false;
1458 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1459 AllocationFamily(AF_IfNameIndex));
1460 C.addTransition(State);
1472 if (BuffType.isNull() || !BuffType->isVoidPointerType())
1478 const CallEvent &
Call,
1479 CheckerContext &
C)
const {
1480 bool IsKnownToBeAllocatedMemory =
false;
1481 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1491 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1494 auto RetVal = State->getSVal(BufArg,
Call.getStackFrame());
1495 State = State->BindExpr(CE,
C.getStackFrame(), RetVal);
1496 C.addTransition(State);
1502 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1503 AllocationFamily(AF_CXXNew));
1504 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1507 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1508 AllocationFamily(AF_CXXNewArray));
1509 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1512 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1513 AllocationFamily(AF_CXXNew));
1515 case OO_Array_Delete:
1516 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1517 AllocationFamily(AF_CXXNewArray));
1520 assert(
false &&
"not a new/delete operator");
1524 C.addTransition(State);
1528 CheckerContext &
C)
const {
1529 SValBuilder &svalBuilder =
C.getSValBuilder();
1531 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1532 AllocationFamily(AF_Malloc));
1533 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1534 C.addTransition(State);
1538 CheckerContext &
C)
const {
1539 State = MallocMemAux(
C,
Call,
Call.getArgExpr(1), UnknownVal(), State,
1540 AllocationFamily(AF_Malloc));
1541 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1542 C.addTransition(State);
1546 CheckerContext &
C)
const {
1547 SVal
Init = UndefinedVal();
1548 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1549 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1550 AllocationFamily(AF_Malloc));
1551 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1552 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1553 C.addTransition(State);
1557 CheckerContext &
C)
const {
1558 SValBuilder &SB =
C.getSValBuilder();
1560 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1561 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1562 AllocationFamily(AF_Malloc));
1563 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1564 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1565 C.addTransition(State);
1570 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1575 const CallEvent &
Call,
1576 CheckerContext &
C)
const {
1590 bool IsKnownToBeAllocated =
false;
1591 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1592 IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1595 C.addTransition(State);
1599 const CallEvent &
Call,
1600 CheckerContext &
C)
const {
1608 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1614 if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||
1615 SizeOpt->isUnknownOrUndef())
1618 const auto LinePtr = LinePtrOpt->getAs<DefinedSVal>();
1619 const auto Size = SizeOpt->getAs<DefinedSVal>();
1620 const MemRegion *LinePtrReg = LinePtr->getAsRegion();
1626 AllocationFamily(AF_Malloc), *LinePtr));
1630 CheckerContext &
C)
const {
1631 State = ReallocMemAux(
C,
Call,
false, State,
1632 AllocationFamily(AF_Malloc),
1634 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1635 State = ProcessZeroAllocCheck(
C,
Call, 2, State);
1636 C.addTransition(State);
1640 const CallEvent &
Call,
1641 CheckerContext &
C)
const {
1642 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1645 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1648 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1649 MismatchedDeallocatorChecker.isEnabled()) {
1654 switch (I->getOwnKind()) {
1655 case OwnershipAttr::Returns:
1656 State = MallocMemReturnsAttr(
C,
Call, I, State);
1658 case OwnershipAttr::Takes:
1659 case OwnershipAttr::Holds:
1660 State = FreeMemAttr(
C,
Call, I, State);
1665 C.addTransition(State);
1668bool MallocChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
1669 if (!
Call.getOriginExpr())
1674 if (
const CheckFn *Callback = FreeingMemFnMap.lookup(
Call)) {
1675 (*Callback)(
this, State,
Call,
C);
1679 if (
const CheckFn *Callback = AllocatingMemFnMap.lookup(
Call)) {
1680 State = MallocBindRetVal(
C,
Call, State,
false);
1681 (*Callback)(
this, State,
Call,
C);
1685 if (
const CheckFn *Callback = ReallocatingMemFnMap.lookup(
Call)) {
1686 State = MallocBindRetVal(
C,
Call, State,
false);
1687 (*Callback)(
this, State,
Call,
C);
1692 State = MallocBindRetVal(
C,
Call, State,
false);
1693 checkCXXNewOrCXXDelete(State,
Call,
C);
1698 checkCXXNewOrCXXDelete(State,
Call,
C);
1702 if (
const CheckFn *Callback = AllocaMemFnMap.lookup(
Call)) {
1703 State = MallocBindRetVal(
C,
Call, State,
true);
1704 (*Callback)(
this, State,
Call,
C);
1708 if (isFreeingOwnershipAttrCall(
Call) || isAllocatingOwnershipAttrCall(
Call)) {
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.getStackFrame());
1747 State->getSVal(Arg,
Call.getStackFrame()).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);
1787 while (!PointeeType.isNull()) {
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.getStackFrame()->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 StackFrame *SF =
C.getPredecessor()->getStackFrame();
1946 DefinedSVal RetVal =
1950 return State->BindExpr(CE,
C.getStackFrame(), 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 StackFrame *SF =
C.getPredecessor()->getStackFrame();
2033 SVal RetVal = State->getSVal(CE,
C.getStackFrame());
2036 State = State->bindDefaultInitial(RetVal,
Init, SF);
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.getStackFrame());
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,
2306 R =
R->StripCasts();
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);
2376 RegionOffset Offset =
R->getAsOffset();
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.getStackFrame(),
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.getStackFrame());
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 (NSF == LeakStackFrame || NSF->
isParentOf(LeakStackFrame))
3015 return LeakInfo(AllocNode, ReferenceRegion);
3018void MallocChecker::HandleLeak(
SymbolRef Sym, ExplodedNode *N,
3019 CheckerContext &
C)
const {
3020 assert(N &&
"HandleLeak is only called with a non-null node");
3022 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3023 assert(RS &&
"cannot leak an untracked symbol");
3024 AllocationFamily Family = RS->getAllocationFamily();
3026 if (Family.Kind == AF_Alloca)
3029 const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);
3033 if (!Frontend || !Frontend->isEnabled())
3039 PathDiagnosticLocation LocUsedForUniqueing;
3040 const ExplodedNode *AllocNode =
nullptr;
3041 const MemRegion *Region =
nullptr;
3042 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
3047 AllocationStmt,
C.getSourceManager(), AllocNode->
getStackFrame());
3049 SmallString<200> buf;
3050 llvm::raw_svector_ostream os(buf);
3052 os <<
"Potential leak of memory pointed to by ";
3055 os <<
"Potential memory leak";
3058 auto R = std::make_unique<PathSensitiveBugReport>(
3059 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3061 R->markInteresting(Sym);
3062 R->addVisitor<MallocBugVisitor>(Sym,
true);
3063 if (ShouldRegisterNoOwnershipChangeVisitor)
3064 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
3065 C.emitReport(std::move(R));
3068void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3069 CheckerContext &
C)
const
3072 RegionStateTy OldRS = state->get<RegionState>();
3073 RegionStateTy::Factory &F = state->get_context<RegionState>();
3075 RegionStateTy RS = OldRS;
3076 SmallVector<SymbolRef, 2> Errors;
3077 for (
auto [Sym, State] : RS) {
3078 if (SymReaper.
isDead(Sym)) {
3079 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3080 Errors.push_back(Sym);
3082 RS = F.remove(RS, Sym);
3088 assert(state->get<ReallocPairs>() ==
3089 C.getState()->get<ReallocPairs>());
3090 assert(state->get<FreeReturnValue>() ==
3091 C.getState()->get<FreeReturnValue>());
3096 ReallocPairsTy RP = state->get<ReallocPairs>();
3097 for (
auto [Sym, ReallocPair] : RP) {
3098 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
3099 state = state->remove<ReallocPairs>(Sym);
3104 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3105 for (
auto [Sym, RetSym] : FR) {
3106 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
3107 state = state->remove<FreeReturnValue>(Sym);
3112 ExplodedNode *N =
C.getPredecessor();
3113 if (!Errors.empty()) {
3114 N =
C.generateNonFatalErrorNode(
C.getState());
3117 HandleLeak(Sym, N,
C);
3122 C.addTransition(state->set<RegionState>(RS), N);
3129 return Name ==
"unique_ptr" || Name ==
"shared_ptr";
3136 if (
const auto *TST = QT->
getAs<TemplateSpecializationType>()) {
3137 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
3160 llvm::SmallPtrSetImpl<const MemRegion *> *
Out;
3163 llvm::SmallPtrSetImpl<const MemRegion *> &
Out)
3176 C->getState()->getLValue(BaseDecl,
Reg->getAs<
SubRegion>(), IsVirtual);
3181 return std::nullopt;
3197 std::optional<FieldConsumer> FC = std::nullopt) {
3210 BaseSpec.getType()->getAsCXXRecordDecl()) {
3211 std::optional<FieldConsumer> NewFC;
3213 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());
3231 if (!T->isRecordType() || T->isReferenceType())
3263 const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(
Call.getDecl());
3267 const auto *RD = CD->getParent();
3272 for (
const auto *Param : CD->parameters()) {
3273 QualType ParamType = Param->getType();
3288 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {
3305 for (
unsigned I = 0, E = std::min(
Call.getNumArgs(), CD->getNumParams());
3307 const Expr *ArgExpr =
Call.getArgExpr(I);
3311 QualType ParamType = CD->getParamDecl(I)->
getType();
3315 SVal ArgVal =
Call.getArgSVal(I);
3317 if (Sym && State->contains<RegionState>(Sym)) {
3318 const RefState *RS = State->get<RegionState>(Sym);
3319 if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {
3320 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3336 return handleSmartPointerConstructorArguments(
Call, State);
3340 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;
3341 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3342 const Expr *AE =
Call.getArgExpr(I);
3351 SVal ArgVal =
Call.getArgSVal(I);
3352 const MemRegion *ArgRegion = ArgVal.
getAsRegion();
3355 SmartPtrFieldRoots);
3359 if (!SmartPtrFieldRoots.empty()) {
3360 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(
3361 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());
3362 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(
3363 SmartPtrFieldRootsVec, State);
3369void MallocChecker::checkPostCall(
const CallEvent &
Call,
3370 CheckerContext &
C)
const {
3372 if (
const auto *PostFN = PostFnMap.lookup(
Call)) {
3373 (*PostFN)(
this,
C.getState(),
Call,
C);
3378 C.addTransition(handleSmartPointerRelatedCalls(
Call,
C,
C.getState()));
3381void MallocChecker::checkPreCall(
const CallEvent &
Call,
3382 CheckerContext &
C)
const {
3384 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3385 const CXXDeleteExpr *DE = DC->getOriginExpr();
3391 if (!NewDeleteChecker.isEnabled())
3399 bool IsKnownToBeAllocated;
3402 false, IsKnownToBeAllocated,
3403 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3405 C.addTransition(State);
3416 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3417 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3421 HandleDoubleFree(
C, SourceRange(),
true, Sym,
3429 if (
const auto *PreFN = PreFnMap.lookup(
Call)) {
3430 (*PreFN)(
this,
C.getState(),
Call,
C);
3438 if (
const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&
Call)) {
3439 const FunctionDecl *FD = FC->getDecl();
3446 if (MallocChecker.isEnabled() && isFreeingCall(
Call))
3451 if (
const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&
Call)) {
3452 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3453 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3458 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3459 SVal ArgSVal =
Call.getArgSVal(I);
3464 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3470void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3471 CheckerContext &
C)
const {
3472 checkEscapeOnReturn(S,
C);
3478void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3479 CheckerContext &
C)
const {
3480 checkEscapeOnReturn(S,
C);
3483void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3484 CheckerContext &
C)
const {
3494 SVal RetVal =
C.getSVal(E);
3501 if (
const SymbolicRegion *BMR =
3503 Sym = BMR->getSymbol();
3507 checkUseAfterFree(Sym,
C, E);
3513void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3514 CheckerContext &
C)
const {
3522 const BlockDataRegion *
R =
3525 auto ReferencedVars =
R->referenced_vars();
3526 if (ReferencedVars.empty())
3529 SmallVector<const MemRegion *, 10> Regions;
3530 MemRegionManager &MemMgr =
C.getSValBuilder().getRegionManager();
3532 for (
const auto &Var : ReferencedVars) {
3533 const VarRegion *VR = Var.getCapturedRegion();
3537 Regions.push_back(VR);
3541 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3542 C.addTransition(state);
3547 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3548 return (RS && RS->isReleased());
3551bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3552 const CallEvent &
Call, CheckerContext &
C)
const {
3553 if (
Call.getNumArgs() == 0)
3556 StringRef FunctionStr =
"";
3557 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3558 if (
const Stmt *Body = FD->
getBody())
3559 if (Body->getBeginLoc().isValid())
3563 C.getSourceManager(),
C.getLangOpts());
3566 if (!FunctionStr.contains(
"__isl_"))
3572 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3573 if (
const RefState *RS = State->get<RegionState>(Sym))
3574 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3576 C.addTransition(State);
3580bool MallocChecker::checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
3581 const Stmt *S)
const {
3591void MallocChecker::checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
3592 const Stmt *S)
const {
3595 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3596 if (RS->isAllocatedOfSizeZero())
3597 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3599 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3605void MallocChecker::checkLocation(SVal l,
bool isLoad,
const Stmt *S,
3606 CheckerContext &
C)
const {
3609 checkUseAfterFree(Sym,
C, S);
3610 checkUseZeroAllocated(Sym,
C, S);
3618 bool Assumption)
const {
3619 RegionStateTy RS = state->get<RegionState>();
3620 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3622 ConstraintManager &CMgr = state->getConstraintManager();
3623 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3625 state = state->remove<RegionState>(Sym);
3630 ReallocPairsTy RP = state->get<ReallocPairs>();
3631 for (
auto [Sym, ReallocPair] : RP) {
3633 ConstraintManager &CMgr = state->getConstraintManager();
3634 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3638 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3639 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3640 if (RS->isReleased()) {
3641 switch (ReallocPair.Kind) {
3642 case OAR_ToBeFreedAfterFailure:
3643 state = state->set<RegionState>(ReallocSym,
3644 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3646 case OAR_DoNotTrackAfterFailure:
3647 state = state->remove<RegionState>(ReallocSym);
3650 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3654 state = state->remove<ReallocPairs>(Sym);
3660bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3661 const CallEvent *
Call,
3665 EscapingSymbol =
nullptr;
3675 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(
Call)) {
3678 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3691 return *FreeWhenDone;
3697 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3698 if (FirstSlot.ends_with(
"NoCopy"))
3705 if (FirstSlot.starts_with(
"addPointer") ||
3706 FirstSlot.starts_with(
"insertPointer") ||
3707 FirstSlot.starts_with(
"replacePointer") ||
3708 FirstSlot ==
"valueWithPointer") {
3715 if (Msg->getMethodFamily() ==
OMF_init) {
3716 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3732 if (isMemCall(*
Call))
3736 if (!
Call->isInSystemHeader())
3743 StringRef FName = II->
getName();
3747 if (FName.ends_with(
"NoCopy")) {
3751 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3752 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3753 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3754 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3755 if (DeallocatorName ==
"kCFAllocatorNull")
3766 if (FName ==
"funopen")
3767 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3773 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3774 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3775 if (
Call->getNumArgs() >= 1) {
3777 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3778 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3779 if (D->getCanonicalDecl()->getName().contains(
"std"))
3789 if (FName ==
"CGBitmapContextCreate" ||
3790 FName ==
"CGBitmapContextCreateWithData" ||
3791 FName ==
"CVPixelBufferCreateWithBytes" ||
3792 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3793 FName ==
"OSAtomicEnqueue") {
3797 if (FName ==
"postEvent" &&
3802 if (FName ==
"connectImpl" &&
3807 if (FName ==
"singleShotImpl" &&
3817 if (FName ==
"GetOwnedMessageInternal") {
3825 if (
Call->argumentsMayEscape())
3835 const CallEvent *
Call,
3837 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3843 const CallEvent *
Call,
3846 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3851 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3852 RS->getAllocationFamily().Kind == AF_CXXNew);
3858 bool IsConstPointerEscape)
const {
3863 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3870 if (EscapingSymbol && EscapingSymbol != sym)
3873 if (
const RefState *RS = State->get<RegionState>(sym))
3874 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3876 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3881bool MallocChecker::isArgZERO_SIZE_PTR(
ProgramStateRef State, CheckerContext &
C,
3882 SVal ArgVal)
const {
3883 if (!KernelZeroSizePtrValue)
3884 KernelZeroSizePtrValue =
3887 const llvm::APSInt *ArgValKnown =
3888 C.getSValBuilder().getKnownValue(State, ArgVal);
3889 return ArgValKnown && *KernelZeroSizePtrValue &&
3890 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3895 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3896 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3898 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3900 if (!currMap.lookup(sym))
3910 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3911 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3912 N.contains_insensitive(
"intrusive") ||
3913 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3922 BugReporterContext &BRC,
3923 PathSensitiveBugReport &BR) {
3927 const RefState *RSCurr = state->get<RegionState>(Sym);
3928 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3933 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3946 if (ReleaseFunctionSF && (ReleaseFunctionSF == CurrentSF ||
3948 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3951 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3952 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3958 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
3961 if (
const auto *MD =
3963 const CXXRecordDecl *RD = MD->getParent();
3981 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3982 SmallString<256> Buf;
3983 llvm::raw_svector_ostream
OS(Buf);
3986 if (isAllocated(RSCurr, RSPrev, S)) {
3987 Msg =
"Memory is allocated";
3988 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3989 Sym,
"Returned allocated memory");
3991 const auto Family = RSCurr->getAllocationFamily();
3992 switch (Family.Kind) {
3997 case AF_CXXNewArray:
3998 case AF_IfNameIndex:
3999 Msg =
"Memory is released";
4000 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4001 Sym,
"Returning; memory was released");
4003 case AF_InnerBuffer: {
4004 const MemRegion *ObjRegion =
4007 QualType ObjTy = TypedRegion->getValueType();
4008 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
4011 OS <<
"deallocated by call to destructor";
4012 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4013 Sym,
"Returning; inner buffer was deallocated");
4015 OS <<
"reallocated by call to '";
4016 const Stmt *S = RSCurr->getStmt();
4017 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
4018 OS << MemCallE->getMethodDecl()->getDeclName();
4019 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
4020 OS << OpCallE->getDirectCallee()->getDeclName();
4021 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
4023 CallEventRef<>
Call =
4025 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
4026 OS << D->getDeclName();
4031 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4032 Sym,
"Returning; inner buffer was reallocated");
4038 assert(
false &&
"Unhandled allocation family!");
4048 ReleaseFunctionSF = CurrentSF;
4051 for (
const StackFrame *SF = CurrentSF; SF; SF = SF->
getParent()) {
4052 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(SF->
getDecl())) {
4088 ReleaseFunctionSF = SF;
4092 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
4093 Msg =
"Memory ownership is transferred";
4094 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
4095 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
4096 Mode = ReallocationFailed;
4097 Msg =
"Reallocation failed";
4098 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
4099 Sym,
"Reallocation failed");
4103 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
4104 "We only support one failed realloc at a time.");
4106 FailedReallocSymbol = sym;
4111 }
else if (Mode == ReallocationFailed) {
4112 assert(FailedReallocSymbol &&
"No symbol to look for.");
4115 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
4117 Msg =
"Attempt to reallocate memory";
4118 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4119 Sym,
"Returned reallocated memory");
4120 FailedReallocSymbol =
nullptr;
4133 PathDiagnosticLocation Pos;
4135 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
4139 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
4145 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
4150void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
4151 const char *NL,
const char *Sep)
const {
4153 RegionStateTy RS = State->get<RegionState>();
4155 if (!RS.isEmpty()) {
4156 Out << Sep <<
"MallocChecker :" << NL;
4157 for (
auto [Sym,
Data] : RS) {
4158 const RefState *RefS = State->get<RegionState>(Sym);
4159 AllocationFamily Family = RefS->getAllocationFamily();
4161 const CheckerFrontend *Frontend =
4162 getRelevantFrontendAs<CheckerFrontend>(Family);
4176namespace allocation_state {
4180 AllocationFamily Family(AF_InnerBuffer);
4181 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
4191 Mgr.
getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);
4199 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
4201 Chk->ShouldRegisterNoOwnershipChangeVisitor =
4203 DMMName,
"AddNoOwnershipChangeNotes");
4206bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
4210#define REGISTER_CHECKER(NAME) \
4211 void ento::register##NAME(CheckerManager &Mgr) { \
4212 Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr); \
4215 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
4224#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)
__device__ __2f16 float __ockl_bool s
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
CanQualType 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.
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