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 StackFrameContext *ReleaseFunctionLC;
993 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
994 : Sym(S), Mode(Normal), FailedReallocSymbol(
nullptr),
995 ReleaseFunctionLC(
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.getLocationContext());
1495 State = State->BindExpr(CE,
C.getLocationContext(), 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)) {
1709 checkOwnershipAttr(State,
Call,
C);
1713 if (isAllocatingOwnershipAttrCall(
Call)) {
1714 State = MallocBindRetVal(
C,
Call, State,
false);
1715 checkOwnershipAttr(State,
Call,
C);
1724 CheckerContext &
C,
const CallEvent &
Call,
const unsigned IndexOfSizeArg,
1729 const Expr *Arg =
nullptr;
1731 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1732 Arg = CE->
getArg(IndexOfSizeArg);
1733 }
else if (
const CXXNewExpr *NE =
1734 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1735 if (
NE->isArray()) {
1736 Arg = *
NE->getArraySize();
1741 assert(
false &&
"not a CallExpr or CXXNewExpr");
1746 RetVal = State->getSVal(
Call.getOriginExpr(),
C.getLocationContext());
1751 State->getSVal(Arg,
Call.getLocationContext()).getAs<DefinedSVal>();
1758 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1762 std::tie(TrueState, FalseState) =
1763 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal,
Zero));
1765 if (TrueState && !FalseState) {
1766 SymbolRef Sym = RetVal->getAsLocSymbol();
1770 const RefState *RS = State->get<RegionState>(Sym);
1772 if (RS->isAllocated())
1773 return TrueState->set<RegionState>(
1774 Sym, RefState::getAllocatedOfSizeZero(RS));
1781 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1790 QualType Result =
T, PointeeType =
T->getPointeeType();
1791 while (!PointeeType.isNull()) {
1792 Result = PointeeType;
1793 PointeeType = PointeeType->getPointeeType();
1806 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1812 for (
const auto *CtorParam : CtorD->
parameters()) {
1815 if (CtorParamPointeeT.
isNull())
1828MallocChecker::processNewAllocation(
const CXXAllocatorCall &
Call,
1830 AllocationFamily Family)
const {
1834 const CXXNewExpr *
NE =
Call.getOriginExpr();
1835 const ParentMap &PM =
C.getLocationContext()->getParentMap();
1849 SVal
Target =
Call.getObjectUnderConstruction();
1850 if (
Call.getOriginExpr()->isArray()) {
1851 if (
auto SizeEx =
NE->getArraySize())
1852 checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1853 AllocationFamily(AF_CXXNewArray));
1857 State = ProcessZeroAllocCheck(
C,
Call, 0, State,
Target);
1861void MallocChecker::checkNewAllocator(
const CXXAllocatorCall &
Call,
1862 CheckerContext &
C)
const {
1863 if (!
C.wasInlined) {
1866 AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1868 C.addTransition(State);
1878 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1879 return FirstSlot ==
"dataWithBytesNoCopy" ||
1880 FirstSlot ==
"initWithBytesNoCopy" ||
1881 FirstSlot ==
"initWithCharactersNoCopy";
1888 for (
unsigned i = 1; i < S.
getNumArgs(); ++i)
1890 return !
Call.getArgSVal(i).isZeroConstant();
1892 return std::nullopt;
1895void MallocChecker::checkPostObjCMessage(
const ObjCMethodCall &
Call,
1896 CheckerContext &
C)
const {
1907 if (
Call.hasNonZeroCallbackArg())
1910 bool IsKnownToBeAllocatedMemory;
1912 true, IsKnownToBeAllocatedMemory,
1913 AllocationFamily(AF_Malloc),
1916 C.addTransition(State);
1920MallocChecker::MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
1921 const OwnershipAttr *Att,
1926 auto attrClassName = Att->getModule()->getName();
1927 auto Family = AllocationFamily(AF_Custom, attrClassName);
1929 if (!Att->args().empty()) {
1930 return MallocMemAux(
C,
Call,
1931 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1932 UnknownVal(), State, Family);
1934 return MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State, Family);
1938 const CallEvent &
Call,
1940 bool isAlloca)
const {
1941 const Expr *CE =
Call.getOriginExpr();
1947 unsigned Count =
C.blockCount();
1948 SValBuilder &SVB =
C.getSValBuilder();
1949 const LocationContext *LCtx =
C.getPredecessor()->getLocationContext();
1950 DefinedSVal RetVal =
1954 return State->BindExpr(CE,
C.getLocationContext(), RetVal);
1958 const CallEvent &
Call,
1959 const Expr *SizeEx, SVal
Init,
1961 AllocationFamily Family)
const {
1966 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
1969void MallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRef State,
1971 llvm::ArrayRef<SymbolRef> TaintedSyms,
1972 AllocationFamily Family)
const {
1973 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State,
this)) {
1975 std::make_unique<PathSensitiveBugReport>(TaintedAllocChecker, Msg, N);
1976 for (
const auto *TaintedSym : TaintedSyms) {
1977 R->markInteresting(TaintedSym);
1979 C.emitReport(std::move(R));
1983void MallocChecker::checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
1985 AllocationFamily Family)
const {
1988 std::vector<SymbolRef> TaintedSyms =
1990 if (TaintedSyms.empty())
1993 SValBuilder &SVB =
C.getSValBuilder();
1999 const llvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
2001 SVB.
makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));
2002 std::optional<NonLoc> SizeNL = SizeSVal.
getAs<NonLoc>();
2003 auto Cmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
2004 .
getAs<DefinedOrUnknownSVal>();
2007 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
2008 if (!StateTooLarge && StateNotTooLarge) {
2013 std::string
Callee =
"Memory allocation function";
2014 if (
Call.getCalleeIdentifier())
2015 Callee =
Call.getCalleeIdentifier()->getName().str();
2017 Callee +
" is called with a tainted (potentially attacker controlled) "
2018 "value. Make sure the value is bound checked.",
2019 State,
C, TaintedSyms, Family);
2023 const CallEvent &
Call, SVal Size,
2025 AllocationFamily Family)
const {
2029 const Expr *CE =
Call.getOriginExpr();
2034 "Allocation functions must return a pointer");
2036 const LocationContext *LCtx =
C.getPredecessor()->getLocationContext();
2037 SVal RetVal = State->getSVal(CE,
C.getLocationContext());
2040 State = State->bindDefaultInitial(RetVal,
Init, LCtx);
2044 Size = UnknownVal();
2046 checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
2050 Size.castAs<DefinedOrUnknownSVal>());
2057 AllocationFamily Family,
2058 std::optional<SVal> RetVal) {
2064 RetVal = State->getSVal(E,
C.getLocationContext());
2067 if (!RetVal->getAs<
Loc>())
2070 SymbolRef Sym = RetVal->getAsLocSymbol();
2078 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
2084 const CallEvent &
Call,
2085 const OwnershipAttr *Att,
2090 auto attrClassName = Att->getModule()->getName();
2091 auto Family = AllocationFamily(AF_Custom, attrClassName);
2093 bool IsKnownToBeAllocated =
false;
2095 for (
const auto &Arg : Att->args()) {
2097 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
2098 Att->getOwnKind() == OwnershipAttr::Holds,
2099 IsKnownToBeAllocated, Family);
2107 const CallEvent &
Call,
2109 bool Hold,
bool &IsKnownToBeAllocated,
2110 AllocationFamily Family,
2111 bool ReturnsNullOnFailure)
const {
2115 if (
Call.getNumArgs() < (
Num + 1))
2118 return FreeMemAux(
C,
Call.getArgExpr(
Num),
Call, State, Hold,
2119 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2126 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
2128 assert(*Ret &&
"We should not store the null return symbol");
2131 RetStatusSymbol = *Ret;
2139 const CallExpr *CE = dyn_cast<CallExpr>(E);
2150 if (I->getOwnKind() != OwnershipAttr::Takes)
2153 os <<
", which takes ownership of '" << I->getModule()->getName() <<
'\'';
2159 if (
const CallExpr *CE = dyn_cast<CallExpr>(E)) {
2175 if (Msg->isInstanceMessage())
2179 Msg->getSelector().print(os);
2183 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
2202 switch (Family.Kind) {
2209 case AF_CXXNewArray:
2212 case AF_IfNameIndex:
2213 os <<
"'if_nameindex()'";
2215 case AF_InnerBuffer:
2216 os <<
"container-specific allocator";
2219 os << Family.CustomName.value();
2223 assert(
false &&
"not a deallocation expression");
2228 switch (Family.Kind) {
2235 case AF_CXXNewArray:
2238 case AF_IfNameIndex:
2239 os <<
"'if_freenameindex()'";
2241 case AF_InnerBuffer:
2242 os <<
"container-specific deallocator";
2245 os <<
"function that takes ownership of '" << Family.CustomName.value()
2250 assert(
false &&
"not a deallocation expression");
2255MallocChecker::FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
2257 bool Hold,
bool &IsKnownToBeAllocated,
2258 AllocationFamily Family,
bool ReturnsNullOnFailure,
2259 std::optional<SVal> ArgValOpt)
const {
2264 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2267 DefinedOrUnknownSVal location = ArgVal.
castAs<DefinedOrUnknownSVal>();
2275 std::tie(notNullState, nullState) = State->assume(location);
2276 if (nullState && !notNullState)
2285 const Expr *ParentExpr =
Call.getOriginExpr();
2304 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2305 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2314 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2321 if (!R->
hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {
2330 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2336 const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->
getBaseRegion());
2343 const RefState *RsBase = State->get<RegionState>(SymBase);
2344 SymbolRef PreviousRetStatusSymbol =
nullptr;
2346 IsKnownToBeAllocated =
2347 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2352 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2358 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2360 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2361 SymBase, PreviousRetStatusSymbol);
2367 if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2368 RsBase->isEscaped()) {
2371 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2372 if (!DeallocMatchesAlloc) {
2374 RsBase, SymBase, Hold);
2384 const Expr *AllocExpr =
cast<Expr>(RsBase->getStmt());
2393 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2399 State = State->remove<FreeReturnValue>(SymBase);
2403 if (ReturnsNullOnFailure) {
2404 SVal RetVal =
C.getSVal(ParentExpr);
2406 if (RetStatusSymbol) {
2407 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2408 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2416 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2421 State = State->invalidateRegions({location},
Call.getCFGElementRef(),
2422 C.blockCount(),
C.getLocationContext(),
2428 return State->set<RegionState>(SymBase,
2429 RefState::getRelinquished(Family,
2432 return State->set<RegionState>(SymBase,
2433 RefState::getReleased(Family, ParentExpr));
2437const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family)
const {
2438 switch (Family.Kind) {
2442 case AF_IfNameIndex:
2443 return MallocChecker.getAs<
T>();
2445 case AF_CXXNewArray: {
2446 const T *ND = NewDeleteChecker.getAs<
T>();
2447 const T *NDL = NewDeleteLeaksChecker.getAs<
T>();
2450 if constexpr (std::is_same_v<T, CheckerFrontend>) {
2451 assert(ND && NDL &&
"Casting to CheckerFrontend always succeeds");
2453 return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;
2455 assert(!(ND && NDL) &&
2456 "NewDelete and NewDeleteLeaks must not share a bug type");
2457 return ND ? ND : NDL;
2459 case AF_InnerBuffer:
2460 return InnerPointerChecker.getAs<
T>();
2462 assert(
false &&
"no family");
2465 assert(
false &&
"unhandled family");
2469const T *MallocChecker::getRelevantFrontendAs(CheckerContext &
C,
2471 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2472 return MallocChecker.getAs<
T>();
2474 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2476 return getRelevantFrontendAs<T>(RS->getAllocationFamily());
2479bool MallocChecker::SummarizeValue(raw_ostream &os, SVal
V) {
2480 if (std::optional<nonloc::ConcreteInt> IntVal =
2481 V.getAs<nonloc::ConcreteInt>())
2482 os <<
"an integer (" << IntVal->getValue() <<
")";
2483 else if (std::optional<loc::ConcreteInt> ConstAddr =
2484 V.getAs<loc::ConcreteInt>())
2485 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2486 else if (std::optional<loc::GotoLabel> Label =
V.getAs<loc::GotoLabel>())
2487 os <<
"the address of the label '" << Label->getLabel()->getName() <<
"'";
2494bool MallocChecker::SummarizeRegion(
ProgramStateRef State, raw_ostream &os,
2495 const MemRegion *MR) {
2497 case MemRegion::FunctionCodeRegionKind: {
2500 os <<
"the address of the function '" << *FD <<
'\'';
2502 os <<
"the address of a function";
2505 case MemRegion::BlockCodeRegionKind:
2508 case MemRegion::BlockDataRegionKind:
2516 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2524 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2526 os <<
"the address of a local stack variable";
2531 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2539 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2541 os <<
"the address of a parameter";
2546 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2555 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2557 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2559 os <<
"the address of a global variable";
2568void MallocChecker::HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal,
2570 const Expr *DeallocExpr,
2571 AllocationFamily Family)
const {
2572 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2575 if (!Frontend->isEnabled()) {
2580 if (ExplodedNode *N =
C.generateErrorNode()) {
2581 SmallString<100> buf;
2582 llvm::raw_svector_ostream os(buf);
2585 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2586 MR = ER->getSuperRegion();
2588 os <<
"Argument to ";
2590 os <<
"deallocator";
2594 MR ? SummarizeRegion(
C.getState(), os, MR) : SummarizeValue(os, ArgVal);
2596 os <<
", which is not memory allocated by ";
2598 os <<
"not memory allocated by ";
2602 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2604 R->markInteresting(MR);
2606 C.emitReport(std::move(R));
2610void MallocChecker::HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
2611 SourceRange Range)
const {
2612 const FreeAlloca *Frontend;
2614 if (MallocChecker.isEnabled())
2615 Frontend = &MallocChecker;
2616 else if (MismatchedDeallocatorChecker.isEnabled())
2617 Frontend = &MismatchedDeallocatorChecker;
2623 if (ExplodedNode *N =
C.generateErrorNode()) {
2624 auto R = std::make_unique<PathSensitiveBugReport>(
2625 Frontend->FreeAllocaBug,
2626 "Memory allocated by 'alloca()' should not be deallocated", N);
2629 C.emitReport(std::move(R));
2633void MallocChecker::HandleMismatchedDealloc(CheckerContext &
C,
2635 const Expr *DeallocExpr,
2637 bool OwnershipTransferred)
const {
2638 if (!MismatchedDeallocatorChecker.isEnabled()) {
2643 if (ExplodedNode *N =
C.generateErrorNode()) {
2644 SmallString<100> buf;
2645 llvm::raw_svector_ostream os(buf);
2647 const Expr *AllocExpr =
cast<Expr>(RS->getStmt());
2648 SmallString<20> AllocBuf;
2649 llvm::raw_svector_ostream AllocOs(AllocBuf);
2650 SmallString<20> DeallocBuf;
2651 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2653 if (OwnershipTransferred) {
2655 os << DeallocOs.str() <<
" cannot";
2659 os <<
" take ownership of memory";
2662 os <<
" allocated by " << AllocOs.str();
2666 os <<
" allocated by " << AllocOs.str();
2668 os <<
" should be deallocated by ";
2672 os <<
", not " << DeallocOs.str();
2677 auto R = std::make_unique<PathSensitiveBugReport>(
2678 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);
2679 R->markInteresting(Sym);
2681 R->addVisitor<MallocBugVisitor>(Sym);
2682 C.emitReport(std::move(R));
2686void MallocChecker::HandleOffsetFree(CheckerContext &
C, SVal ArgVal,
2687 SourceRange Range,
const Expr *DeallocExpr,
2688 AllocationFamily Family,
2689 const Expr *AllocExpr)
const {
2690 const OffsetFree *Frontend = getRelevantFrontendAs<OffsetFree>(Family);
2693 if (!Frontend->isEnabled()) {
2698 ExplodedNode *N =
C.generateErrorNode();
2702 SmallString<100> buf;
2703 llvm::raw_svector_ostream os(buf);
2704 SmallString<20> AllocNameBuf;
2705 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2708 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2714 "Only symbols with a valid offset can have offset free errors");
2716 int offsetBytes = Offset.
getOffset() /
C.getASTContext().getCharWidth();
2718 os <<
"Argument to ";
2720 os <<
"deallocator";
2721 os <<
" is offset by "
2724 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2725 <<
" from the start of ";
2727 os <<
"memory allocated by " << AllocNameOs.str();
2729 os <<
"allocated memory";
2731 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->OffsetFreeBug,
2735 C.emitReport(std::move(R));
2738void MallocChecker::HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
2740 const UseFree *Frontend = getRelevantFrontendAs<UseFree>(
C, Sym);
2743 if (!Frontend->isEnabled()) {
2748 if (ExplodedNode *N =
C.generateErrorNode()) {
2749 AllocationFamily AF =
2750 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2752 auto R = std::make_unique<PathSensitiveBugReport>(
2753 Frontend->UseFreeBug,
2754 AF.Kind == AF_InnerBuffer
2755 ?
"Inner pointer of container used after re/deallocation"
2756 :
"Use of memory after it is released",
2759 R->markInteresting(Sym);
2761 R->addVisitor<MallocBugVisitor>(Sym);
2763 if (AF.Kind == AF_InnerBuffer)
2766 C.emitReport(std::move(R));
2770void MallocChecker::HandleDoubleFree(CheckerContext &
C, SourceRange Range,
2773 const DoubleFree *Frontend = getRelevantFrontendAs<DoubleFree>(
C, Sym);
2776 if (!Frontend->isEnabled()) {
2781 if (ExplodedNode *N =
C.generateErrorNode()) {
2782 auto R = std::make_unique<PathSensitiveBugReport>(
2783 Frontend->DoubleFreeBug,
2784 (Released ?
"Attempt to release already released memory"
2785 :
"Attempt to release non-owned memory"),
2787 if (
Range.isValid())
2789 R->markInteresting(Sym);
2791 R->markInteresting(PrevSym);
2792 R->addVisitor<MallocBugVisitor>(Sym);
2793 C.emitReport(std::move(R));
2797void MallocChecker::HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
2799 const UseZeroAllocated *Frontend =
2800 getRelevantFrontendAs<UseZeroAllocated>(
C, Sym);
2803 if (!Frontend->isEnabled()) {
2808 if (ExplodedNode *N =
C.generateErrorNode()) {
2809 auto R = std::make_unique<PathSensitiveBugReport>(
2810 Frontend->UseZeroAllocatedBug,
"Use of memory allocated with size zero",
2815 R->markInteresting(Sym);
2816 R->addVisitor<MallocBugVisitor>(Sym);
2818 C.emitReport(std::move(R));
2822void MallocChecker::HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal,
2824 const Expr *FreeExpr,
2825 AllocationFamily Family)
const {
2826 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2829 if (!Frontend->isEnabled()) {
2834 if (ExplodedNode *N =
C.generateErrorNode()) {
2835 SmallString<100> Buf;
2836 llvm::raw_svector_ostream Os(Buf);
2839 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2840 MR = ER->getSuperRegion();
2842 Os <<
"Argument to ";
2844 Os <<
"deallocator";
2846 Os <<
" is a function pointer";
2848 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2850 R->markInteresting(MR);
2852 C.emitReport(std::move(R));
2857MallocChecker::ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
2859 AllocationFamily Family,
bool SuffixWithN)
const {
2868 const Expr *arg0Expr = CE->
getArg(0);
2869 SVal Arg0Val =
C.getSVal(arg0Expr);
2872 DefinedOrUnknownSVal arg0Val = Arg0Val.
castAs<DefinedOrUnknownSVal>();
2874 SValBuilder &svalBuilder =
C.getSValBuilder();
2876 DefinedOrUnknownSVal PtrEQ = svalBuilder.
evalEQ(
2877 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2880 const Expr *Arg1 = CE->
getArg(1);
2883 SVal TotalSize =
C.getSVal(Arg1);
2885 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2890 DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(
2891 State, TotalSize.
castAs<DefinedOrUnknownSVal>(),
2892 svalBuilder.makeIntValWithWidth(
2893 svalBuilder.getContext().getCanonicalSizeType(), 0));
2896 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2898 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2901 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2902 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2906 if (PrtIsNull && !SizeIsZero) {
2908 C,
Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
2913 if (PrtIsNull && SizeIsZero)
2918 bool IsKnownToBeAllocated =
false;
2927 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2932 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2935 MallocMemAux(
C,
Call, TotalSize, UnknownVal(), stateFree, Family);
2939 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2940 if (ShouldFreeOnFail)
2941 Kind = OAR_FreeOnFailure;
2942 else if (!IsKnownToBeAllocated)
2943 Kind = OAR_DoNotTrackAfterFailure;
2947 SVal RetVal = stateRealloc->getSVal(CE,
C.getLocationContext());
2949 assert(FromPtr && ToPtr &&
2950 "By this point, FreeMemAux and MallocMemAux should have checked "
2951 "whether the argument or the return value is symbolic!");
2955 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2956 ReallocPair(FromPtr, Kind));
2958 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2959 return stateRealloc;
2965 const CallEvent &
Call,
2970 if (
Call.getNumArgs() < 2)
2973 SValBuilder &svalBuilder =
C.getSValBuilder();
2976 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2978 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State,
2979 AllocationFamily(AF_Malloc));
2982MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2984 CheckerContext &
C) {
2988 const ExplodedNode *AllocNode = N;
2989 const MemRegion *ReferenceRegion =
nullptr;
2993 if (!State->get<RegionState>(Sym))
2998 if (!ReferenceRegion) {
2999 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
3000 SVal Val = State->getSVal(MR);
3006 ReferenceRegion = MR;
3014 if (NContext == LeakContext ||
3020 return LeakInfo(AllocNode, ReferenceRegion);
3023void MallocChecker::HandleLeak(
SymbolRef Sym, ExplodedNode *N,
3024 CheckerContext &
C)
const {
3025 assert(N &&
"HandleLeak is only called with a non-null node");
3027 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3028 assert(RS &&
"cannot leak an untracked symbol");
3029 AllocationFamily Family = RS->getAllocationFamily();
3031 if (Family.Kind == AF_Alloca)
3034 const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);
3038 if (!Frontend || !Frontend->isEnabled())
3044 PathDiagnosticLocation LocUsedForUniqueing;
3045 const ExplodedNode *AllocNode =
nullptr;
3046 const MemRegion *Region =
nullptr;
3047 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
3052 C.getSourceManager(),
3055 SmallString<200> buf;
3056 llvm::raw_svector_ostream os(buf);
3058 os <<
"Potential leak of memory pointed to by ";
3061 os <<
"Potential memory leak";
3064 auto R = std::make_unique<PathSensitiveBugReport>(
3065 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3067 R->markInteresting(Sym);
3068 R->addVisitor<MallocBugVisitor>(Sym,
true);
3069 if (ShouldRegisterNoOwnershipChangeVisitor)
3070 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
3071 C.emitReport(std::move(R));
3074void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3075 CheckerContext &
C)
const
3078 RegionStateTy OldRS = state->get<RegionState>();
3079 RegionStateTy::Factory &F = state->get_context<RegionState>();
3081 RegionStateTy RS = OldRS;
3082 SmallVector<SymbolRef, 2> Errors;
3083 for (
auto [Sym, State] : RS) {
3084 if (SymReaper.
isDead(Sym)) {
3085 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3086 Errors.push_back(Sym);
3088 RS = F.remove(RS, Sym);
3094 assert(state->get<ReallocPairs>() ==
3095 C.getState()->get<ReallocPairs>());
3096 assert(state->get<FreeReturnValue>() ==
3097 C.getState()->get<FreeReturnValue>());
3102 ReallocPairsTy RP = state->get<ReallocPairs>();
3103 for (
auto [Sym, ReallocPair] : RP) {
3104 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
3105 state = state->remove<ReallocPairs>(Sym);
3110 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3111 for (
auto [Sym, RetSym] : FR) {
3112 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
3113 state = state->remove<FreeReturnValue>(Sym);
3118 ExplodedNode *N =
C.getPredecessor();
3119 if (!Errors.empty()) {
3120 N =
C.generateNonFatalErrorNode(
C.getState());
3123 HandleLeak(Sym, N,
C);
3128 C.addTransition(state->set<RegionState>(RS), N);
3135 return Name ==
"unique_ptr" || Name ==
"shared_ptr";
3142 if (
const auto *TST = QT->
getAs<TemplateSpecializationType>()) {
3143 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
3166 llvm::SmallPtrSetImpl<const MemRegion *> *
Out;
3169 llvm::SmallPtrSetImpl<const MemRegion *> &
Out)
3182 C->getState()->getLValue(BaseDecl,
Reg->getAs<
SubRegion>(), IsVirtual);
3187 return std::nullopt;
3203 std::optional<FieldConsumer> FC = std::nullopt) {
3216 BaseSpec.getType()->getAsCXXRecordDecl()) {
3217 std::optional<FieldConsumer> NewFC;
3219 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());
3237 if (!
T->isRecordType() ||
T->isReferenceType())
3269 const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(
Call.getDecl());
3273 const auto *RD = CD->getParent();
3278 for (
const auto *Param : CD->parameters()) {
3279 QualType ParamType = Param->getType();
3294 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {
3311 for (
unsigned I = 0, E = std::min(
Call.getNumArgs(), CD->getNumParams());
3313 const Expr *ArgExpr =
Call.getArgExpr(I);
3317 QualType ParamType = CD->getParamDecl(I)->
getType();
3321 SVal ArgVal =
Call.getArgSVal(I);
3323 if (Sym && State->contains<RegionState>(Sym)) {
3324 const RefState *RS = State->get<RegionState>(Sym);
3325 if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {
3326 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3342 return handleSmartPointerConstructorArguments(
Call, State);
3346 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;
3347 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3348 const Expr *AE =
Call.getArgExpr(I);
3357 SVal ArgVal =
Call.getArgSVal(I);
3358 const MemRegion *ArgRegion = ArgVal.
getAsRegion();
3361 SmartPtrFieldRoots);
3365 if (!SmartPtrFieldRoots.empty()) {
3366 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(
3367 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());
3368 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(
3369 SmartPtrFieldRootsVec, State);
3375void MallocChecker::checkPostCall(
const CallEvent &
Call,
3376 CheckerContext &
C)
const {
3378 if (
const auto *PostFN = PostFnMap.lookup(
Call)) {
3379 (*PostFN)(
this,
C.getState(),
Call,
C);
3384 C.addTransition(handleSmartPointerRelatedCalls(
Call,
C,
C.getState()));
3387void MallocChecker::checkPreCall(
const CallEvent &
Call,
3388 CheckerContext &
C)
const {
3390 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3391 const CXXDeleteExpr *DE = DC->getOriginExpr();
3397 if (!NewDeleteChecker.isEnabled())
3405 bool IsKnownToBeAllocated;
3408 false, IsKnownToBeAllocated,
3409 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3411 C.addTransition(State);
3422 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3423 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3427 HandleDoubleFree(
C, SourceRange(),
true, Sym,
3435 if (
const auto *PreFN = PreFnMap.lookup(
Call)) {
3436 (*PreFN)(
this,
C.getState(),
Call,
C);
3444 if (
const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&
Call)) {
3445 const FunctionDecl *FD = FC->getDecl();
3452 if (MallocChecker.isEnabled() && isFreeingCall(
Call))
3457 if (
const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&
Call)) {
3458 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3459 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3464 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3465 SVal ArgSVal =
Call.getArgSVal(I);
3470 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3476void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3477 CheckerContext &
C)
const {
3478 checkEscapeOnReturn(S,
C);
3484void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3485 CheckerContext &
C)
const {
3486 checkEscapeOnReturn(S,
C);
3489void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3490 CheckerContext &
C)
const {
3500 SVal RetVal =
C.getSVal(E);
3507 if (
const SymbolicRegion *BMR =
3509 Sym = BMR->getSymbol();
3513 checkUseAfterFree(Sym,
C, E);
3519void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3520 CheckerContext &
C)
const {
3528 const BlockDataRegion *R =
3532 if (ReferencedVars.empty())
3535 SmallVector<const MemRegion*, 10> Regions;
3536 const LocationContext *LC =
C.getLocationContext();
3537 MemRegionManager &MemMgr =
C.getSValBuilder().getRegionManager();
3539 for (
const auto &Var : ReferencedVars) {
3540 const VarRegion *VR = Var.getCapturedRegion();
3544 Regions.push_back(VR);
3548 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3549 C.addTransition(state);
3554 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3555 return (RS && RS->isReleased());
3558bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3559 const CallEvent &
Call, CheckerContext &
C)
const {
3560 if (
Call.getNumArgs() == 0)
3563 StringRef FunctionStr =
"";
3564 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3565 if (
const Stmt *Body = FD->
getBody())
3566 if (Body->getBeginLoc().isValid())
3570 C.getSourceManager(),
C.getLangOpts());
3573 if (!FunctionStr.contains(
"__isl_"))
3579 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3580 if (
const RefState *RS = State->get<RegionState>(Sym))
3581 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3583 C.addTransition(State);
3587bool MallocChecker::checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
3588 const Stmt *S)
const {
3598void MallocChecker::checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
3599 const Stmt *S)
const {
3602 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3603 if (RS->isAllocatedOfSizeZero())
3604 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3606 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3612void MallocChecker::checkLocation(SVal l,
bool isLoad,
const Stmt *S,
3613 CheckerContext &
C)
const {
3616 checkUseAfterFree(Sym,
C, S);
3617 checkUseZeroAllocated(Sym,
C, S);
3625 bool Assumption)
const {
3626 RegionStateTy RS = state->get<RegionState>();
3627 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3629 ConstraintManager &CMgr = state->getConstraintManager();
3630 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3632 state = state->remove<RegionState>(Sym);
3637 ReallocPairsTy RP = state->get<ReallocPairs>();
3638 for (
auto [Sym, ReallocPair] : RP) {
3640 ConstraintManager &CMgr = state->getConstraintManager();
3641 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3645 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3646 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3647 if (RS->isReleased()) {
3648 switch (ReallocPair.Kind) {
3649 case OAR_ToBeFreedAfterFailure:
3650 state = state->set<RegionState>(ReallocSym,
3651 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3653 case OAR_DoNotTrackAfterFailure:
3654 state = state->remove<RegionState>(ReallocSym);
3657 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3661 state = state->remove<ReallocPairs>(Sym);
3667bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3668 const CallEvent *
Call,
3672 EscapingSymbol =
nullptr;
3682 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(
Call)) {
3685 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3698 return *FreeWhenDone;
3704 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3705 if (FirstSlot.ends_with(
"NoCopy"))
3712 if (FirstSlot.starts_with(
"addPointer") ||
3713 FirstSlot.starts_with(
"insertPointer") ||
3714 FirstSlot.starts_with(
"replacePointer") ||
3715 FirstSlot ==
"valueWithPointer") {
3722 if (Msg->getMethodFamily() ==
OMF_init) {
3723 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3739 if (isMemCall(*
Call))
3743 if (!
Call->isInSystemHeader())
3750 StringRef FName = II->
getName();
3754 if (FName.ends_with(
"NoCopy")) {
3758 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3759 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3760 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3761 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3762 if (DeallocatorName ==
"kCFAllocatorNull")
3773 if (FName ==
"funopen")
3774 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3780 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3781 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3782 if (
Call->getNumArgs() >= 1) {
3784 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3785 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3786 if (D->getCanonicalDecl()->getName().contains(
"std"))
3796 if (FName ==
"CGBitmapContextCreate" ||
3797 FName ==
"CGBitmapContextCreateWithData" ||
3798 FName ==
"CVPixelBufferCreateWithBytes" ||
3799 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3800 FName ==
"OSAtomicEnqueue") {
3804 if (FName ==
"postEvent" &&
3809 if (FName ==
"connectImpl" &&
3814 if (FName ==
"singleShotImpl" &&
3824 if (FName ==
"GetOwnedMessageInternal") {
3832 if (
Call->argumentsMayEscape())
3842 const CallEvent *
Call,
3844 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3850 const CallEvent *
Call,
3853 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3858 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3859 RS->getAllocationFamily().Kind == AF_CXXNew);
3865 bool IsConstPointerEscape)
const {
3870 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3877 if (EscapingSymbol && EscapingSymbol != sym)
3880 if (
const RefState *RS = State->get<RegionState>(sym))
3881 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3883 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3888bool MallocChecker::isArgZERO_SIZE_PTR(
ProgramStateRef State, CheckerContext &
C,
3889 SVal ArgVal)
const {
3890 if (!KernelZeroSizePtrValue)
3891 KernelZeroSizePtrValue =
3894 const llvm::APSInt *ArgValKnown =
3895 C.getSValBuilder().getKnownValue(State, ArgVal);
3896 return ArgValKnown && *KernelZeroSizePtrValue &&
3897 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3902 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3903 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3905 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3907 if (!currMap.lookup(sym))
3917 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3918 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3919 N.contains_insensitive(
"intrusive") ||
3920 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3929 BugReporterContext &BRC,
3930 PathSensitiveBugReport &BR) {
3934 const RefState *RSCurr = state->get<RegionState>(Sym);
3935 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3940 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3953 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
3955 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3958 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3959 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3965 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
3968 if (
const auto *MD =
3970 const CXXRecordDecl *RD = MD->getParent();
3988 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3989 SmallString<256> Buf;
3990 llvm::raw_svector_ostream
OS(Buf);
3993 if (isAllocated(RSCurr, RSPrev, S)) {
3994 Msg =
"Memory is allocated";
3995 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3996 Sym,
"Returned allocated memory");
3998 const auto Family = RSCurr->getAllocationFamily();
3999 switch (Family.Kind) {
4004 case AF_CXXNewArray:
4005 case AF_IfNameIndex:
4006 Msg =
"Memory is released";
4007 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4008 Sym,
"Returning; memory was released");
4010 case AF_InnerBuffer: {
4011 const MemRegion *ObjRegion =
4014 QualType ObjTy = TypedRegion->getValueType();
4015 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
4018 OS <<
"deallocated by call to destructor";
4019 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4020 Sym,
"Returning; inner buffer was deallocated");
4022 OS <<
"reallocated by call to '";
4023 const Stmt *S = RSCurr->getStmt();
4024 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
4025 OS << MemCallE->getMethodDecl()->getDeclName();
4026 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
4027 OS << OpCallE->getDirectCallee()->getDeclName();
4028 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
4030 CallEventRef<>
Call =
4032 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
4033 OS << D->getDeclName();
4038 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4039 Sym,
"Returning; inner buffer was reallocated");
4045 assert(
false &&
"Unhandled allocation family!");
4058 for (
const LocationContext *LC = CurrentLC; LC; LC = LC->
getParent()) {
4059 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
4099 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
4100 Msg =
"Memory ownership is transferred";
4101 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
4102 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
4103 Mode = ReallocationFailed;
4104 Msg =
"Reallocation failed";
4105 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
4106 Sym,
"Reallocation failed");
4110 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
4111 "We only support one failed realloc at a time.");
4113 FailedReallocSymbol = sym;
4118 }
else if (Mode == ReallocationFailed) {
4119 assert(FailedReallocSymbol &&
"No symbol to look for.");
4122 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
4124 Msg =
"Attempt to reallocate memory";
4125 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4126 Sym,
"Returned reallocated memory");
4127 FailedReallocSymbol =
nullptr;
4140 PathDiagnosticLocation Pos;
4142 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
4146 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
4153 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
4158void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
4159 const char *NL,
const char *Sep)
const {
4161 RegionStateTy RS = State->get<RegionState>();
4163 if (!RS.isEmpty()) {
4164 Out << Sep <<
"MallocChecker :" << NL;
4165 for (
auto [Sym,
Data] : RS) {
4166 const RefState *RefS = State->get<RegionState>(Sym);
4167 AllocationFamily Family = RefS->getAllocationFamily();
4169 const CheckerFrontend *Frontend =
4170 getRelevantFrontendAs<CheckerFrontend>(Family);
4184namespace allocation_state {
4188 AllocationFamily Family(AF_InnerBuffer);
4189 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
4199 Mgr.
getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);
4207 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
4209 Chk->ShouldRegisterNoOwnershipChangeVisitor =
4211 DMMName,
"AddNoOwnershipChangeNotes");
4214bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
4218#define REGISTER_CHECKER(NAME) \
4219 void ento::register##NAME(CheckerManager &Mgr) { \
4220 Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr); \
4223 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
#define REGISTER_CHECKER(name)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::Target Target
static bool isRvalueByValueRecordWithSmartPtr(const Expr *AE)
Check if an expression is an rvalue record with smart owning pointer fields passed by value.
static bool isFromStdNamespace(const CallEvent &Call)
static bool isStandardNew(const FunctionDecl *FD)
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
static QualType getDeepPointeeType(QualType T)
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)
Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.
static void collectSmartPtrFieldRegions(const MemRegion *Reg, QualType RecQT, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
Collect memory regions of smart owning pointer fields from a record type (including fields from base ...
static bool hasSmartPtrField(const CXXRecordDecl *CRD, std::optional< FieldConsumer > FC=std::nullopt)
Check if a record type has smart owning pointer fields (directly or in base classes).
static bool isStandardDelete(const FunctionDecl *FD)
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static bool isSmartPtrType(QualType QT)
static bool isStandardNewDelete(const T &FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
static bool isRvalueByValueRecord(const Expr *AE)
Check if an expression is an rvalue record type passed by value.
#define BUGTYPE_PROVIDER(NAME, DEF)
static bool isGRealloc(const CallEvent &Call)
static const Expr * getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD)
static bool isSmartPtrRecord(const CXXRecordDecl *RD)
Check if a CXXRecordDecl has a name matching recognized smart pointer names.
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)
Print expected name of a deallocator based on the allocator's family.
static bool isStandardRealloc(const CallEvent &Call)
static bool isSmartPtrCall(const CallEvent &Call)
Check if a call is a constructor of a smart owning pointer class that accepts pointer parameters.
static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)
Checks if the previous call to free on the given symbol failed - if free failed, returns true.
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)
Update the RefState to reflect the new memory allocation.
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
static bool isSmartPtrName(StringRef Name)
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
__device__ __2f16 float __ockl_bool s
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
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.
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
An expression that sends a message to the given Objective-C object or class.
bool isConsumedExpr(Expr *E) const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
field_range fields() const
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
unsigned getNumArgs() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
The base class of all kinds of template declarations (e.g., class, function, etc.).
NamedDecl * getTemplatedDecl() const
Get the underlying, templated declaration.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isVoidPointerType() const
bool isFunctionPointerType() const
bool isPointerType() const
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
APSIntPtr getMaxValue(const llvm::APSInt &v)
llvm::iterator_range< referenced_vars_iterator > referenced_vars() const
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
ProgramStateManager & getStateManager() const
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
An immutable map from CallDescriptions to arbitrary data.
CallEventRef getSimpleCall(const CallExpr *E, ProgramStateRef State, const LocationContext *LCtx, CFGBlock::ConstCFGElementRef ElemRef)
Represents an abstract call to a function or method along a particular path.
Checker families (where a single backend class implements multiple related frontends) should derive f...
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
CheckerNameRef getName() const
const AnalyzerOptions & getAnalyzerOptions() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
const ProgramStateRef & getState() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
static bool isLocType(QualType T)
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
MemRegion - The root abstract class for all memory regions.
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
bool hasMemorySpace(ProgramStateRef State) const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
Represents any expression that calls an Objective-C method.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
void addCallStackHint(PathDiagnosticPieceRef Piece, std::unique_ptr< StackHintGenerator > StackHint)
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
CallEventManager & getCallEventManager()
bool hasSymbolicOffset() const
int64_t getOffset() const
DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned Count)
Conjure a symbol representing heap allocated memory region.
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isUnknownOrUndef() const
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
const MemRegion * getAsRegion() const
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
virtual void dumpToStream(raw_ostream &os) const
virtual QualType getType() const =0
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
SymbolRef getSymbol() const
It might return null.
const VarDecl * getDecl() const override=0
const StackFrameContext * getStackFrame() const
It might return null.
Defines the clang::TargetInfo interface.
__inline void unsigned int _2
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDeleteExpr > cxxDeleteExpr
Matches delete expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)
This function provides an additional visitor that augments the bug report with information relevant t...
const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)
'Sym' represents a pointer to the inner buffer of a container object.
const char *const MemoryError
const char *const TaintedData
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given Statement and state.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent)
Set the dynamic extent Extent of the region MR.
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::optional< SVal > getPointeeVal(SVal PtrSVal, ProgramStateRef State)
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool NE(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
bool isa(CodeGen::Address addr)
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
const FunctionProtoType * T
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