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 {
203 return K == AllocatedOfAnySize || K == AllocatedOfSizeZero;
205 bool isAllocatedOfSizeZero()
const {
return K == AllocatedOfSizeZero; }
206 bool isReleased()
const {
return K == Released; }
207 bool isRelinquished()
const {
return K == Relinquished; }
208 bool isEscaped()
const {
return K == Escaped; }
209 AllocationFamily getAllocationFamily()
const {
return Family; }
210 const Stmt *getStmt()
const {
return S; }
213 return K ==
X.K && S ==
X.S && Family ==
X.Family;
216 static RefState getAllocated(AllocationFamily F,
const Stmt *S) {
217 return RefState(AllocatedOfAnySize, S, F);
219 static RefState getAllocatedOfSizeZero(
const RefState *RS) {
220 return RefState(AllocatedOfSizeZero, RS->getStmt(),
221 RS->getAllocationFamily());
223 static RefState getReleased(AllocationFamily family,
const Stmt *s) {
224 return RefState(Released, s, family);
226 static RefState getRelinquished(AllocationFamily family,
const Stmt *s) {
227 return RefState(Relinquished, s, family);
229 static RefState getEscaped(
const RefState *RS) {
230 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
233 void Profile(llvm::FoldingSetNodeID &ID)
const {
239 LLVM_DUMP_METHOD
void dump(raw_ostream &
OS)
const {
241 case AllocatedOfAnySize:
244#define CASE(ID) case ID: OS << #ID; break;
245 CASE(AllocatedOfSizeZero)
252 LLVM_DUMP_METHOD
void dump()
const {
dump(llvm::errs()); }
267 AllocationFamily Family,
268 std::optional<SVal> RetVal = std::nullopt);
282enum OwnershipAfterReallocKind {
284 OAR_ToBeFreedAfterFailure,
294 OAR_DoNotTrackAfterFailure
307 OwnershipAfterReallocKind Kind;
309 ReallocPair(
SymbolRef S, OwnershipAfterReallocKind K)
310 : ReallocatedSym(S), Kind(K) {}
311 void Profile(llvm::FoldingSetNodeID &ID)
const {
313 ID.AddPointer(ReallocatedSym);
316 return ReallocatedSym ==
X.ReallocatedSym &&
352#define BUGTYPE_PROVIDER(NAME, DEF) \
353 struct NAME : virtual public CheckerFrontend { \
354 BugType NAME##Bug{this, DEF, categories::MemoryError}; \
376#undef BUGTYPE_PROVIDER
378template <
typename... BT_PROVIDERS>
379struct DynMemFrontend :
virtual public CheckerFrontend,
public BT_PROVIDERS... {
380 template <
typename T>
const T *getAs()
const {
381 if constexpr (std::is_same_v<T, CheckerFrontend> ||
382 (std::is_same_v<T, BT_PROVIDERS> || ...))
383 return static_cast<const T *
>(
this);
394 check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape,
395 check::PreStmt<ReturnStmt>, check::EndFunction, check::PreCall,
396 check::PostCall, eval::Call, check::NewAllocator,
397 check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location,
404 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
406 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
414 bool ModelAllocationFailure =
false;
423 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
426 DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
428 DynMemFrontend<Leak> NewDeleteLeaksChecker;
429 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
430 DynMemFrontend<UseFree> InnerPointerChecker;
433 CheckerFrontendWithBugType TaintedAllocChecker{
"Tainted Memory Allocation",
436 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
438 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
439 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
440 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
443 handleSmartPointerConstructorArguments(
const CallEvent &
Call,
448 void checkNewAllocator(
const CXXAllocatorCall &
Call, CheckerContext &
C)
const;
449 void checkPostObjCMessage(
const ObjCMethodCall &
Call, CheckerContext &
C)
const;
450 void checkPostStmt(
const BlockExpr *BE, CheckerContext &
C)
const;
451 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &
C)
const;
452 void checkPreStmt(
const ReturnStmt *S, CheckerContext &
C)
const;
453 void checkEndFunction(
const ReturnStmt *S, CheckerContext &
C)
const;
455 bool Assumption)
const;
456 void checkLocation(SVal l,
bool isLoad,
const Stmt *S,
457 CheckerContext &
C)
const;
461 const CallEvent *
Call,
465 const CallEvent *
Call,
469 const char *NL,
const char *Sep)
const override;
471 StringRef getDebugTag()
const override {
return "MallocChecker"; }
474#define CHECK_FN(NAME) \
475 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
507 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},
508 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},
511 const CallDescriptionMap<CheckFn> PostFnMap{
514 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},
515 {{CDM::CLibrary, {
"getdelim"}, 4},
516 &MallocChecker::checkGetDelimOrGetLine},
519 const CallDescriptionMap<CheckFn> FreeingMemFnMap{
520 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
521 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
522 &MallocChecker::checkIfFreeNameIndex},
523 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
524 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
527 bool isFreeingCall(
const CallEvent &
Call)
const;
528 static bool isFreeingOwnershipAttrCall(
const FunctionDecl *
Func);
529 static bool isFreeingOwnershipAttrCall(
const CallEvent &
Call);
530 static bool isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func);
531 static bool isAllocatingOwnershipAttrCall(
const CallEvent &
Call);
533 friend class NoMemOwnershipChangeVisitor;
535 CallDescriptionMap<CheckFn> AllocaMemFnMap{
536 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
537 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
541 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
542 &MallocChecker::checkAlloca},
545 CallDescriptionMap<CheckFn> AllocatingMemFnMap{
546 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAllocMayFail},
547 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
548 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
549 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
550 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
551 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
552 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
553 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
554 {{CDM::CLibrary, {
"if_nameindex"}, 0}, &MallocChecker::checkIfNameIndex},
555 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
556 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
557 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
558 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
559 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
560 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
561 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
562 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
563 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
564 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
565 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
568 CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
569 {{CDM::CLibrary, {
"realloc"}, 2},
570 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
571 {{CDM::CLibrary, {
"reallocf"}, 2},
572 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
true)},
573 {{CDM::CLibrary, {
"g_realloc"}, 2},
574 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
575 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
576 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
577 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
578 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
581 bool isMemCall(
const CallEvent &
Call)
const;
582 void reportTaintBug(StringRef Msg,
ProgramStateRef State, CheckerContext &
C,
583 llvm::ArrayRef<SymbolRef> TaintedSyms,
584 AllocationFamily Family)
const;
586 void checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
588 AllocationFamily Family)
const;
591 mutable std::optional<uint64_t> KernelZeroFlagVal;
593 using KernelZeroSizePtrValueTy = std::optional<int>;
598 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
603 processNewAllocation(
const CXXAllocatorCall &
Call, CheckerContext &
C,
604 AllocationFamily Family)
const;
615 ProcessZeroAllocCheck(CheckerContext &
C,
const CallEvent &
Call,
617 std::optional<SVal> RetVal = std::nullopt);
636 MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
646 const CallEvent &
Call,
648 bool isAlloca)
const;
660 MallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
const Expr *SizeEx,
673 const CallEvent &
Call, SVal Size,
675 AllocationFamily Family)
const;
688 llvm::ArrayRef<unsigned> SizeArgIndexes = {})
const;
692 [[nodiscard]] std::optional<ProgramStateRef>
693 performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
714 const CallEvent &
Call,
715 const OwnershipAttr *Att,
739 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
740 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
764 FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
const CallEvent &
Call,
766 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
767 std::optional<SVal> ArgValOpt = {})
const;
783 ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
bool ShouldFreeOnFail,
785 bool SuffixWithN =
false)
const;
792 [[nodiscard]]
static SVal evalMulForBufferSize(CheckerContext &
C,
794 const Expr *BlockBytes);
802 const CallEvent &
Call,
807 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
808 CheckerContext &
C)
const;
811 bool checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
const Stmt *S)
const;
815 void checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
816 const Stmt *S)
const;
829 bool ignoreDirectEscapeTo(
const CallEvent *
Call,
837 bool IsConstPointerEscape)
const;
840 void checkEscapeOnReturn(
const ReturnStmt *S, CheckerContext &
C)
const;
849 const T *getRelevantFrontendAs(AllocationFamily Family)
const;
852 const T *getRelevantFrontendAs(CheckerContext &
C,
SymbolRef Sym)
const;
854 static bool SummarizeValue(raw_ostream &os, SVal
V);
856 const MemRegion *MR);
858 void HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal, SourceRange Range,
859 const Expr *DeallocExpr,
860 AllocationFamily Family)
const;
862 void HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
863 SourceRange Range)
const;
865 void HandleMismatchedDealloc(CheckerContext &
C, SourceRange Range,
866 const Expr *DeallocExpr,
const RefState *RS,
867 SymbolRef Sym,
bool OwnershipTransferred)
const;
869 void HandleOffsetFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
870 const Expr *DeallocExpr, AllocationFamily Family,
871 const Expr *AllocExpr =
nullptr)
const;
873 void HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
876 void HandleDoubleFree(CheckerContext &
C, SourceRange Range,
bool Released,
879 void HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
882 void HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal, SourceRange Range,
883 const Expr *FreeExpr,
884 AllocationFamily Family)
const;
888 static LeakInfo getAllocationSite(
const ExplodedNode *N,
SymbolRef Sym,
891 void HandleLeak(
SymbolRef Sym, ExplodedNode *N, CheckerContext &
C)
const;
904class NoMemOwnershipChangeVisitor final :
public NoOwnershipChangeVisitor {
913 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
914 const auto *MallocChk =
static_cast<const MallocChecker *
>(&Checker);
915 if (MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
916 MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
919 if (
const auto *
Func =
920 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
921 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
928 return CallEnterState->get<RegionState>(Sym) !=
929 CallExitEndState->get<RegionState>(Sym);
936 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
937 ASTContext &ACtx)
final {
938 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
953 using namespace clang::ast_matchers;
958 for (BoundNodes
Match : Matches) {
959 if (
Match.getNodeAs<CXXDeleteExpr>(
"delete"))
962 if (
const auto *
Call =
Match.getNodeAs<CallExpr>(
"call"))
963 if (isFreeingCallAsWritten(*
Call))
975 N->getState()->getStateManager().getContext().getSourceManager());
976 return std::make_shared<PathDiagnosticEventPiece>(
977 L,
"Returning without deallocating memory or storing the pointer for "
978 "later deallocation");
982 NoMemOwnershipChangeVisitor(
SymbolRef Sym,
const MallocChecker *Checker)
983 : NoOwnershipChangeVisitor(Sym, Checker) {}
985 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1004 enum NotificationMode { Normal, ReallocationFailed };
1010 NotificationMode Mode;
1017 const StackFrame *ReleaseFunctionSF;
1022 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
1023 : Sym(S), Mode(Normal), FailedReallocSymbol(
nullptr),
1024 ReleaseFunctionSF(
nullptr), IsLeak(isLeak) {}
1026 static void *getTag() {
1031 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1032 ID.AddPointer(getTag());
1037 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
1039 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
1040 (RSCurr && RSCurr->isAllocated())) &&
1041 (!RSPrev || !RSPrev->isAllocated());
1046 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
1049 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
1050 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
1051 (!Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
1056 static inline bool isRelinquished(
const RefState *RSCurr,
1057 const RefState *RSPrev,
const Stmt *Stmt) {
1059 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
1060 (RSCurr && RSCurr->isRelinquished()) &&
1061 (!RSPrev || !RSPrev->isRelinquished()));
1068 static inline bool hasReallocFailed(
const RefState *RSCurr,
1069 const RefState *RSPrev,
1071 return ((!isa_and_nonnull<CallExpr>(Stmt)) &&
1072 (RSCurr && RSCurr->isAllocated())) &&
1073 (RSPrev && !RSPrev->isAllocated());
1077 BugReporterContext &BRC,
1078 PathSensitiveBugReport &BR)
override;
1081 BugReporterContext &BRC,
1082 PathSensitiveBugReport &BR)
override {
1088 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1093 class StackHintGeneratorForReallocationFailed
1094 :
public StackHintGeneratorForSymbol {
1096 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1097 : StackHintGeneratorForSymbol(S, M) {}
1099 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1103 SmallString<200> buf;
1104 llvm::raw_svector_ostream os(buf);
1106 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1107 <<
" parameter failed";
1109 return std::string(os.str());
1112 std::string getMessageForReturn(
const CallExpr *CallExpr)
override {
1113 return "Reallocation of returned value failed";
1131 bool VisitSymbol(
SymbolRef sym)
override {
1132 state = state->remove<RegionState>(sym);
1152 explicit EscapeTrackedCallback(
ProgramStateRef S) : State(std::move(S)) {}
1155 bool VisitSymbol(
SymbolRef Sym)
override {
1156 if (
const RefState *RS = State->get<RegionState>(Sym)) {
1157 if (RS->isAllocated()) {
1158 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
1166 EscapeTrackedRegionsReachableFrom(ArrayRef<const MemRegion *> Roots,
1173 SmallVector<const MemRegion *, 10> Regions;
1174 EscapeTrackedCallback Visitor(State);
1175 for (
const MemRegion *R : Roots) {
1176 Regions.push_back(R);
1178 State->scanReachableSymbols(Regions, Visitor);
1179 return Visitor.State;
1182 friend class SymbolVisitor;
1191 if (Kind != OO_New && Kind != OO_Array_New)
1207 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1218 return L.
isInvalid() || (!HasBody && SM.isInSystemHeader(L));
1225bool MallocChecker::isFreeingOwnershipAttrCall(
const CallEvent &
Call) {
1226 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1228 return Func && isFreeingOwnershipAttrCall(
Func);
1231bool MallocChecker::isFreeingOwnershipAttrCall(
const FunctionDecl *
Func) {
1232 if (
Func->hasAttrs()) {
1233 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1234 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1235 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1242bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1246 return isFreeingOwnershipAttrCall(
Call);
1249bool MallocChecker::isAllocatingOwnershipAttrCall(
const CallEvent &
Call) {
1250 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1252 return Func && isAllocatingOwnershipAttrCall(
Func);
1255bool MallocChecker::isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func) {
1256 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1257 if (I->getOwnKind() == OwnershipAttr::Returns)
1264bool MallocChecker::isMemCall(
const CallEvent &
Call)
const {
1269 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1272 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1273 return Func &&
Func->hasAttr<OwnershipAttr>();
1276std::optional<ProgramStateRef>
1277MallocChecker::performKernelMalloc(
const CallEvent &
Call, CheckerContext &
C,
1295 ASTContext &Ctx =
C.getASTContext();
1298 if (!KernelZeroFlagVal) {
1300 case llvm::Triple::FreeBSD:
1301 KernelZeroFlagVal = 0x0100;
1303 case llvm::Triple::NetBSD:
1304 KernelZeroFlagVal = 0x0002;
1306 case llvm::Triple::OpenBSD:
1307 KernelZeroFlagVal = 0x0008;
1309 case llvm::Triple::Linux:
1311 KernelZeroFlagVal = 0x8000;
1319 return std::nullopt;
1326 if (
Call.getNumArgs() < 2)
1327 return std::nullopt;
1329 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1330 const SVal
V =
C.getSVal(FlagsEx);
1334 return std::nullopt;
1337 NonLoc Flags =
V.castAs<NonLoc>();
1338 NonLoc ZeroFlag =
C.getSValBuilder()
1339 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1341 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1344 if (MaskedFlagsUC.isUnknownOrUndef())
1345 return std::nullopt;
1346 DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
1350 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1353 if (TrueState && !FalseState) {
1354 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1355 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1356 AllocationFamily(AF_Malloc));
1359 return std::nullopt;
1362SVal MallocChecker::evalMulForBufferSize(CheckerContext &
C,
const Expr *Blocks,
1363 const Expr *BlockBytes) {
1364 SValBuilder &SB =
C.getSValBuilder();
1365 SVal BlocksVal =
C.getSVal(Blocks);
1366 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1368 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1374 const CallEvent &
Call,
1375 CheckerContext &
C)
const {
1376 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1377 AllocationFamily(AF_Malloc));
1378 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1379 C.addTransition(State);
1383 const CallEvent &
Call,
1384 CheckerContext &
C)
const {
1385 C.addTransition(FailedAlloc(
C,
Call, State, {0}));
1387 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1388 AllocationFamily(AF_Malloc));
1389 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1390 C.addTransition(State);
1394 const CallEvent &
Call,
1395 CheckerContext &
C)
const {
1396 std::optional<ProgramStateRef> MaybeState =
1397 performKernelMalloc(
Call,
C, State);
1399 State = *MaybeState;
1401 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1402 AllocationFamily(AF_Malloc));
1403 C.addTransition(State);
1427 bool ShouldFreeOnFail)
const {
1437 if (StandardRealloc)
1438 C.addTransition(FailedAlloc(
C,
Call, State, {1}));
1440 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1441 AllocationFamily(AF_Malloc));
1442 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1443 C.addTransition(State);
1447 CheckerContext &
C)
const {
1448 C.addTransition(FailedAlloc(
C,
Call, State, {0, 1}));
1450 State = CallocMem(
C,
Call, State);
1451 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1452 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1453 C.addTransition(State);
1457 CheckerContext &
C)
const {
1458 bool IsKnownToBeAllocatedMemory =
false;
1459 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1461 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1462 AllocationFamily(AF_Malloc));
1463 C.addTransition(State);
1467 CheckerContext &
C)
const {
1468 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), UndefinedVal(), State,
1469 AllocationFamily(AF_Alloca));
1470 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1471 C.addTransition(State);
1475 CheckerContext &
C)
const {
1476 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1480 C.addTransition(FailedAlloc(
C,
Call, State));
1482 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1483 AllocationFamily(AF_Malloc));
1484 C.addTransition(State);
1488 const CallEvent &
Call,
1489 CheckerContext &
C)
const {
1490 C.addTransition(FailedAlloc(
C,
Call, State));
1494 State = MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State,
1495 AllocationFamily(AF_IfNameIndex));
1496 C.addTransition(State);
1500 const CallEvent &
Call,
1501 CheckerContext &
C)
const {
1502 bool IsKnownToBeAllocatedMemory =
false;
1503 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1504 AllocationFamily(AF_IfNameIndex));
1505 C.addTransition(State);
1517 if (BuffType.isNull() || !BuffType->isVoidPointerType())
1523 const CallEvent &
Call,
1524 CheckerContext &
C)
const {
1525 bool IsKnownToBeAllocatedMemory =
false;
1526 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1536 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1539 auto RetVal = State->getSVal(BufArg,
Call.getStackFrame());
1540 State = State->BindExpr(CE,
C.getStackFrame(), RetVal);
1541 C.addTransition(State);
1547 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1548 AllocationFamily(AF_CXXNew));
1549 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1552 State = MallocMemAux(
C,
Call, CE->getArg(0), UndefinedVal(), State,
1553 AllocationFamily(AF_CXXNewArray));
1554 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1557 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1558 AllocationFamily(AF_CXXNew));
1560 case OO_Array_Delete:
1561 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1562 AllocationFamily(AF_CXXNewArray));
1565 assert(
false &&
"not a new/delete operator");
1569 C.addTransition(State);
1573 CheckerContext &
C)
const {
1574 SValBuilder &svalBuilder =
C.getSValBuilder();
1576 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1577 AllocationFamily(AF_Malloc));
1578 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1579 C.addTransition(State);
1583 CheckerContext &
C)
const {
1584 State = MallocMemAux(
C,
Call,
Call.getArgExpr(1), UnknownVal(), State,
1585 AllocationFamily(AF_Malloc));
1586 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1587 C.addTransition(State);
1591 CheckerContext &
C)
const {
1592 SVal
Init = UndefinedVal();
1593 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1594 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1595 AllocationFamily(AF_Malloc));
1596 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1597 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1598 C.addTransition(State);
1602 CheckerContext &
C)
const {
1603 SValBuilder &SB =
C.getSValBuilder();
1605 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1606 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1607 AllocationFamily(AF_Malloc));
1608 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1609 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1610 C.addTransition(State);
1615 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1620 const CallEvent &
Call,
1621 CheckerContext &
C)
const {
1635 bool IsKnownToBeAllocated =
false;
1636 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1637 IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1640 C.addTransition(State);
1644 const CallEvent &
Call,
1645 CheckerContext &
C)
const {
1653 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1659 if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||
1660 SizeOpt->isUnknownOrUndef())
1663 const auto LinePtr = LinePtrOpt->getAs<DefinedSVal>();
1664 const auto Size = SizeOpt->getAs<DefinedSVal>();
1665 const MemRegion *LinePtrReg = LinePtr->getAsRegion();
1671 AllocationFamily(AF_Malloc), *LinePtr));
1675 CheckerContext &
C)
const {
1676 State = ReallocMemAux(
C,
Call,
false, State,
1677 AllocationFamily(AF_Malloc),
1679 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1680 State = ProcessZeroAllocCheck(
C,
Call, 2, State);
1681 C.addTransition(State);
1685 const CallEvent &
Call,
1686 CheckerContext &
C)
const {
1687 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1690 const FunctionDecl *FD =
C.getCalleeDecl(CE);
1693 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1694 MismatchedDeallocatorChecker.isEnabled()) {
1699 switch (I->getOwnKind()) {
1700 case OwnershipAttr::Returns:
1701 State = MallocMemReturnsAttr(
C,
Call, I, State);
1703 case OwnershipAttr::Takes:
1704 case OwnershipAttr::Holds:
1705 State = FreeMemAttr(
C,
Call, I, State);
1710 C.addTransition(State);
1713bool MallocChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
1714 if (!
Call.getOriginExpr())
1720 (*Callback)(
this, State,
Call,
C);
1725 State = MallocBindRetVal(
C,
Call, State,
false);
1726 (*Callback)(
this, State,
Call,
C);
1731 State = MallocBindRetVal(
C,
Call, State,
false);
1732 (*Callback)(
this, State,
Call,
C);
1737 State = MallocBindRetVal(
C,
Call, State,
false);
1738 checkCXXNewOrCXXDelete(State,
Call,
C);
1743 checkCXXNewOrCXXDelete(State,
Call,
C);
1748 State = MallocBindRetVal(
C,
Call, State,
true);
1749 (*Callback)(
this, State,
Call,
C);
1753 if (isFreeingOwnershipAttrCall(
Call) || isAllocatingOwnershipAttrCall(
Call)) {
1754 if (isAllocatingOwnershipAttrCall(
Call))
1755 State = MallocBindRetVal(
C,
Call, State,
false);
1756 checkOwnershipAttr(State,
Call,
C);
1765 CheckerContext &
C,
const CallEvent &
Call,
const unsigned IndexOfSizeArg,
1770 const Expr *Arg =
nullptr;
1772 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1773 Arg = CE->
getArg(IndexOfSizeArg);
1774 }
else if (
const CXXNewExpr *NE =
1775 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1776 if (
NE->isArray()) {
1777 Arg = *
NE->getArraySize();
1782 assert(
false &&
"not a CallExpr or CXXNewExpr");
1787 RetVal = State->getSVal(
Call.getOriginExpr(),
C.getStackFrame());
1792 State->getSVal(Arg,
Call.getStackFrame()).getAs<DefinedSVal>();
1799 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1803 std::tie(TrueState, FalseState) =
1804 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal,
Zero));
1806 if (TrueState && !FalseState) {
1807 SymbolRef Sym = RetVal->getAsLocSymbol();
1811 const RefState *RS = State->get<RegionState>(Sym);
1813 if (RS->isAllocated() && !RS->isAllocatedOfSizeZero())
1814 return TrueState->set<RegionState>(
1815 Sym, RefState::getAllocatedOfSizeZero(RS));
1822 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1832 while (!PointeeType.isNull()) {
1834 PointeeType = PointeeType->getPointeeType();
1847 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1853 for (
const auto *CtorParam : CtorD->
parameters()) {
1856 if (CtorParamPointeeT.
isNull())
1869MallocChecker::processNewAllocation(
const CXXAllocatorCall &
Call,
1871 AllocationFamily Family)
const {
1875 const CXXNewExpr *
NE =
Call.getOriginExpr();
1876 const ParentMap &PM =
C.getStackFrame()->getParentMap();
1890 SVal
Target =
Call.getObjectUnderConstruction();
1891 if (
Call.getOriginExpr()->isArray()) {
1892 if (
auto SizeEx =
NE->getArraySize())
1893 checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1894 AllocationFamily(AF_CXXNewArray));
1898 State = ProcessZeroAllocCheck(
C,
Call, 0, State,
Target);
1902void MallocChecker::checkNewAllocator(
const CXXAllocatorCall &
Call,
1903 CheckerContext &
C)
const {
1904 if (!
C.wasInlined) {
1907 AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1909 C.addTransition(State);
1919 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1920 return FirstSlot ==
"dataWithBytesNoCopy" ||
1921 FirstSlot ==
"initWithBytesNoCopy" ||
1922 FirstSlot ==
"initWithCharactersNoCopy";
1929 for (
unsigned i = 1; i < S.
getNumArgs(); ++i)
1931 return !
Call.getArgSVal(i).isZeroConstant();
1933 return std::nullopt;
1936void MallocChecker::checkPostObjCMessage(
const ObjCMethodCall &
Call,
1937 CheckerContext &
C)
const {
1948 if (
Call.hasNonZeroCallbackArg())
1951 bool IsKnownToBeAllocatedMemory;
1953 true, IsKnownToBeAllocatedMemory,
1954 AllocationFamily(AF_Malloc),
1957 C.addTransition(State);
1961MallocChecker::MallocMemReturnsAttr(CheckerContext &
C,
const CallEvent &
Call,
1962 const OwnershipAttr *Att,
1967 auto attrClassName = Att->getModule()->getName();
1968 auto Family = AllocationFamily(AF_Custom, attrClassName);
1970 if (!Att->args().empty()) {
1971 return MallocMemAux(
C,
Call,
1972 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1973 UnknownVal(), State, Family);
1975 return MallocMemAux(
C,
Call, UnknownVal(), UnknownVal(), State, Family);
1979 const CallEvent &
Call,
1981 bool isAlloca)
const {
1982 const Expr *CE =
Call.getOriginExpr();
1988 unsigned Count =
C.blockCount();
1989 SValBuilder &SVB =
C.getSValBuilder();
1990 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
1991 DefinedSVal RetVal =
1995 return State->BindExpr(CE,
C.getStackFrame(), RetVal);
1999 const CallEvent &
Call,
2000 const Expr *SizeEx, SVal
Init,
2002 AllocationFamily Family)
const {
2007 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
2010void MallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRef State,
2012 llvm::ArrayRef<SymbolRef> TaintedSyms,
2013 AllocationFamily Family)
const {
2014 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State,
this)) {
2016 std::make_unique<PathSensitiveBugReport>(TaintedAllocChecker, Msg, N);
2017 for (
const auto *TaintedSym : TaintedSyms) {
2018 R->markInteresting(TaintedSym);
2020 C.emitReport(std::move(R));
2024void MallocChecker::checkTaintedness(CheckerContext &
C,
const CallEvent &
Call,
2026 AllocationFamily Family)
const {
2029 std::vector<SymbolRef> TaintedSyms =
2031 if (TaintedSyms.empty())
2034 SValBuilder &SVB =
C.getSValBuilder();
2040 const llvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
2042 SVB.
makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));
2043 std::optional<NonLoc> SizeNL = SizeSVal.
getAs<NonLoc>();
2044 auto Cmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
2045 .
getAs<DefinedOrUnknownSVal>();
2048 auto [StateTooLarge, StateNotTooLarge] = State->assume(*
Cmp);
2049 if (!StateTooLarge && StateNotTooLarge) {
2054 std::string
Callee =
"Memory allocation function";
2055 if (
Call.getCalleeIdentifier())
2056 Callee =
Call.getCalleeIdentifier()->getName().str();
2058 Callee +
" is called with a tainted (potentially attacker controlled) "
2059 "value; make sure the value is bound checked",
2060 State,
C, TaintedSyms, Family);
2064 const CallEvent &
Call, SVal Size,
2066 AllocationFamily Family)
const {
2070 const Expr *CE =
Call.getOriginExpr();
2075 "Allocation functions must return a pointer");
2077 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
2078 SVal RetVal = State->getSVal(CE,
C.getStackFrame());
2082 State = State->bindDefaultInitial(RetVal,
Init, SF);
2086 Size = UnknownVal();
2088 checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
2092 Size.castAs<DefinedOrUnknownSVal>());
2098MallocChecker::FailedAlloc(CheckerContext &
C,
const CallEvent &
Call,
2100 llvm::ArrayRef<unsigned> SizeArgIndexes)
const {
2101 if (!State || !ModelAllocationFailure)
2104 for (
unsigned SizeArgI : SizeArgIndexes) {
2105 auto DefArgVal =
Call.getArgSVal(SizeArgI).getAs<DefinedOrUnknownSVal>();
2108 State = State->assume(*DefArgVal,
true);
2113 auto RetVal = State->getSVal(
Call.getOriginExpr(),
C.getStackFrame())
2114 .castAs<DefinedOrUnknownSVal>();
2115 return State->assume(RetVal,
false);
2120 AllocationFamily Family,
2121 std::optional<SVal> RetVal) {
2127 RetVal = State->getSVal(E,
C.getStackFrame());
2130 if (!RetVal->getAs<
Loc>())
2133 SymbolRef Sym = RetVal->getAsLocSymbol();
2141 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
2147 const CallEvent &
Call,
2148 const OwnershipAttr *Att,
2153 auto attrClassName = Att->getModule()->getName();
2154 auto Family = AllocationFamily(AF_Custom, attrClassName);
2156 bool IsKnownToBeAllocated =
false;
2158 for (
const auto &Arg : Att->args()) {
2160 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
2161 Att->getOwnKind() == OwnershipAttr::Holds,
2162 IsKnownToBeAllocated, Family);
2170 const CallEvent &
Call,
2172 bool Hold,
bool &IsKnownToBeAllocated,
2173 AllocationFamily Family,
2174 bool ReturnsNullOnFailure)
const {
2178 if (
Call.getNumArgs() < (
Num + 1))
2181 return FreeMemAux(
C,
Call.getArgExpr(
Num),
Call, State, Hold,
2182 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2189 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
2191 assert(*Ret &&
"We should not store the null return symbol");
2194 RetStatusSymbol = *Ret;
2202 const CallExpr *CE = dyn_cast<CallExpr>(E);
2213 if (I->getOwnKind() != OwnershipAttr::Takes)
2216 os <<
", which takes ownership of '" << I->getModule()->getName() <<
'\'';
2222 if (
const CallExpr *CE = dyn_cast<CallExpr>(E)) {
2238 if (Msg->isInstanceMessage())
2242 Msg->getSelector().print(os);
2246 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
2265 switch (Family.Kind) {
2272 case AF_CXXNewArray:
2275 case AF_IfNameIndex:
2276 os <<
"'if_nameindex()'";
2278 case AF_InnerBuffer:
2279 os <<
"container-specific allocator";
2282 os << Family.CustomName.value();
2286 assert(
false &&
"not a deallocation expression");
2291 switch (Family.Kind) {
2298 case AF_CXXNewArray:
2301 case AF_IfNameIndex:
2302 os <<
"'if_freenameindex()'";
2304 case AF_InnerBuffer:
2305 os <<
"container-specific deallocator";
2308 os <<
"function that takes ownership of '" << Family.CustomName.value()
2313 assert(
false &&
"not a deallocation expression");
2318MallocChecker::FreeMemAux(CheckerContext &
C,
const Expr *ArgExpr,
2320 bool Hold,
bool &IsKnownToBeAllocated,
2321 AllocationFamily Family,
bool ReturnsNullOnFailure,
2322 std::optional<SVal> ArgValOpt)
const {
2327 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2330 DefinedOrUnknownSVal location = ArgVal.
castAs<DefinedOrUnknownSVal>();
2338 std::tie(notNullState, nullState) = State->assume(location);
2339 if (nullState && !notNullState)
2348 const Expr *ParentExpr =
Call.getOriginExpr();
2367 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2368 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2373 R =
R->StripCasts();
2377 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2384 if (!
R->hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {
2393 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2399 const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(
R->getBaseRegion());
2406 const RefState *RsBase = State->get<RegionState>(SymBase);
2407 SymbolRef PreviousRetStatusSymbol =
nullptr;
2409 IsKnownToBeAllocated = RsBase && RsBase->isAllocated();
2414 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2420 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2422 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2423 SymBase, PreviousRetStatusSymbol);
2429 if (RsBase->isAllocated() || RsBase->isEscaped()) {
2432 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2433 if (!DeallocMatchesAlloc) {
2435 RsBase, SymBase, Hold);
2441 RegionOffset Offset =
R->getAsOffset();
2445 const Expr *AllocExpr =
cast<Expr>(RsBase->getStmt());
2454 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2460 State = State->remove<FreeReturnValue>(SymBase);
2464 if (ReturnsNullOnFailure) {
2465 SVal RetVal =
C.getSVal(ParentExpr);
2467 if (RetStatusSymbol) {
2468 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2469 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2477 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2482 State = State->invalidateRegions({location},
Call.getCFGElementRef(),
2483 C.blockCount(),
C.getStackFrame(),
2489 return State->set<RegionState>(SymBase,
2490 RefState::getRelinquished(Family,
2493 return State->set<RegionState>(SymBase,
2494 RefState::getReleased(Family, ParentExpr));
2498const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family)
const {
2499 switch (Family.Kind) {
2503 case AF_IfNameIndex:
2504 return MallocChecker.getAs<
T>();
2506 case AF_CXXNewArray: {
2507 const T *ND = NewDeleteChecker.getAs<
T>();
2508 const T *NDL = NewDeleteLeaksChecker.getAs<
T>();
2511 if constexpr (std::is_same_v<T, CheckerFrontend>) {
2512 assert(ND && NDL &&
"Casting to CheckerFrontend always succeeds");
2514 return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;
2516 assert(!(ND && NDL) &&
2517 "NewDelete and NewDeleteLeaks must not share a bug type");
2518 return ND ? ND : NDL;
2520 case AF_InnerBuffer:
2521 return InnerPointerChecker.getAs<
T>();
2523 assert(
false &&
"no family");
2526 assert(
false &&
"unhandled family");
2530const T *MallocChecker::getRelevantFrontendAs(CheckerContext &
C,
2532 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2533 return MallocChecker.
getAs<
T>();
2535 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2537 return getRelevantFrontendAs<T>(RS->getAllocationFamily());
2540bool MallocChecker::SummarizeValue(raw_ostream &os, SVal
V) {
2541 if (std::optional<nonloc::ConcreteInt> IntVal =
2542 V.getAs<nonloc::ConcreteInt>())
2543 os <<
"an integer (" << IntVal->getValue() <<
")";
2544 else if (std::optional<loc::ConcreteInt> ConstAddr =
2545 V.getAs<loc::ConcreteInt>())
2546 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2547 else if (std::optional<loc::GotoLabel> Label =
V.getAs<loc::GotoLabel>())
2548 os <<
"the address of the label '" << Label->getLabel()->getName() <<
"'";
2555bool MallocChecker::SummarizeRegion(
ProgramStateRef State, raw_ostream &os,
2556 const MemRegion *MR) {
2558 case MemRegion::FunctionCodeRegionKind: {
2561 os <<
"the address of the function '" << *FD <<
'\'';
2563 os <<
"the address of a function";
2566 case MemRegion::BlockCodeRegionKind:
2569 case MemRegion::BlockDataRegionKind:
2577 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2585 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2587 os <<
"the address of a local stack variable";
2592 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2600 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2602 os <<
"the address of a parameter";
2607 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2616 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2618 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2620 os <<
"the address of a global variable";
2629void MallocChecker::HandleNonHeapDealloc(CheckerContext &
C, SVal ArgVal,
2631 const Expr *DeallocExpr,
2632 AllocationFamily Family)
const {
2633 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2636 if (!Frontend->isEnabled()) {
2641 if (ExplodedNode *N =
C.addSink()) {
2642 SmallString<100> buf;
2643 llvm::raw_svector_ostream os(buf);
2646 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2647 MR = ER->getSuperRegion();
2649 os <<
"Argument to ";
2651 os <<
"deallocator";
2655 MR ? SummarizeRegion(
C.getState(), os, MR) : SummarizeValue(os, ArgVal);
2657 os <<
", which is not memory allocated by ";
2659 os <<
"not memory allocated by ";
2663 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2665 R->markInteresting(MR);
2667 C.emitReport(std::move(R));
2671void MallocChecker::HandleFreeAlloca(CheckerContext &
C, SVal ArgVal,
2672 SourceRange Range)
const {
2673 const FreeAlloca *Frontend;
2675 if (MallocChecker.isEnabled())
2676 Frontend = &MallocChecker;
2677 else if (MismatchedDeallocatorChecker.isEnabled())
2678 Frontend = &MismatchedDeallocatorChecker;
2684 if (ExplodedNode *N =
C.addSink()) {
2685 auto R = std::make_unique<PathSensitiveBugReport>(
2686 Frontend->FreeAllocaBug,
2687 "Memory allocated by 'alloca()' should not be deallocated", N);
2690 C.emitReport(std::move(R));
2694void MallocChecker::HandleMismatchedDealloc(CheckerContext &
C,
2696 const Expr *DeallocExpr,
2698 bool OwnershipTransferred)
const {
2699 if (!MismatchedDeallocatorChecker.isEnabled()) {
2704 if (ExplodedNode *N =
C.addSink()) {
2705 SmallString<100> buf;
2706 llvm::raw_svector_ostream os(buf);
2708 const Expr *AllocExpr =
cast<Expr>(RS->getStmt());
2709 SmallString<20> AllocBuf;
2710 llvm::raw_svector_ostream AllocOs(AllocBuf);
2711 SmallString<20> DeallocBuf;
2712 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2714 if (OwnershipTransferred) {
2716 os << DeallocOs.str() <<
" cannot";
2720 os <<
" take ownership of memory";
2723 os <<
" allocated by " << AllocOs.str();
2727 os <<
" allocated by " << AllocOs.str();
2729 os <<
" should be deallocated by ";
2733 os <<
", not " << DeallocOs.str();
2738 auto R = std::make_unique<PathSensitiveBugReport>(
2739 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);
2740 R->markInteresting(Sym);
2742 R->addVisitor<MallocBugVisitor>(Sym);
2743 C.emitReport(std::move(R));
2747void MallocChecker::HandleOffsetFree(CheckerContext &
C, SVal ArgVal,
2748 SourceRange Range,
const Expr *DeallocExpr,
2749 AllocationFamily Family,
2750 const Expr *AllocExpr)
const {
2751 const OffsetFree *Frontend = getRelevantFrontendAs<OffsetFree>(Family);
2754 if (!Frontend->isEnabled()) {
2759 ExplodedNode *N =
C.addSink();
2763 SmallString<100> buf;
2764 llvm::raw_svector_ostream os(buf);
2765 SmallString<20> AllocNameBuf;
2766 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2769 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2775 "Only symbols with a valid offset can have offset free errors");
2777 int offsetBytes = Offset.
getOffset() /
C.getASTContext().getCharWidth();
2779 os <<
"Argument to ";
2781 os <<
"deallocator";
2782 os <<
" is offset by "
2785 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2786 <<
" from the start of ";
2788 os <<
"memory allocated by " << AllocNameOs.str();
2790 os <<
"allocated memory";
2792 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->OffsetFreeBug,
2796 C.emitReport(std::move(R));
2799void MallocChecker::HandleUseAfterFree(CheckerContext &
C, SourceRange Range,
2801 const UseFree *Frontend = getRelevantFrontendAs<UseFree>(
C, Sym);
2804 if (!Frontend->isEnabled()) {
2809 if (ExplodedNode *N =
C.addSink()) {
2810 AllocationFamily AF =
2811 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2813 auto R = std::make_unique<PathSensitiveBugReport>(
2814 Frontend->UseFreeBug,
2815 AF.Kind == AF_InnerBuffer
2816 ?
"Inner pointer of container used after re/deallocation"
2817 :
"Use of memory after it is released",
2820 R->markInteresting(Sym);
2822 R->addVisitor<MallocBugVisitor>(Sym);
2824 if (AF.Kind == AF_InnerBuffer)
2827 C.emitReport(std::move(R));
2831void MallocChecker::HandleDoubleFree(CheckerContext &
C, SourceRange Range,
2834 const DoubleFree *Frontend = getRelevantFrontendAs<DoubleFree>(
C, Sym);
2837 if (!Frontend->isEnabled()) {
2842 if (ExplodedNode *N =
C.addSink()) {
2843 auto R = std::make_unique<PathSensitiveBugReport>(
2844 Frontend->DoubleFreeBug,
2845 (Released ?
"Attempt to release already released memory"
2846 :
"Attempt to release non-owned memory"),
2848 if (
Range.isValid())
2850 R->markInteresting(Sym);
2852 R->markInteresting(PrevSym);
2853 R->addVisitor<MallocBugVisitor>(Sym);
2854 C.emitReport(std::move(R));
2858void MallocChecker::HandleUseZeroAlloc(CheckerContext &
C, SourceRange Range,
2860 const UseZeroAllocated *Frontend =
2861 getRelevantFrontendAs<UseZeroAllocated>(
C, Sym);
2864 if (!Frontend->isEnabled()) {
2869 if (ExplodedNode *N =
C.addSink()) {
2870 auto R = std::make_unique<PathSensitiveBugReport>(
2871 Frontend->UseZeroAllocatedBug,
"Use of memory allocated with size zero",
2876 R->markInteresting(Sym);
2877 R->addVisitor<MallocBugVisitor>(Sym);
2879 C.emitReport(std::move(R));
2883void MallocChecker::HandleFunctionPtrFree(CheckerContext &
C, SVal ArgVal,
2885 const Expr *FreeExpr,
2886 AllocationFamily Family)
const {
2887 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2890 if (!Frontend->isEnabled()) {
2895 if (ExplodedNode *N =
C.addSink()) {
2896 SmallString<100> Buf;
2897 llvm::raw_svector_ostream Os(Buf);
2900 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2901 MR = ER->getSuperRegion();
2903 Os <<
"Argument to ";
2905 Os <<
"deallocator";
2907 Os <<
" is a function pointer";
2909 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2911 R->markInteresting(MR);
2913 C.emitReport(std::move(R));
2918MallocChecker::ReallocMemAux(CheckerContext &
C,
const CallEvent &
Call,
2920 AllocationFamily Family,
bool SuffixWithN)
const {
2929 const Expr *arg0Expr = CE->
getArg(0);
2930 SVal Arg0Val =
C.getSVal(arg0Expr);
2933 DefinedOrUnknownSVal arg0Val = Arg0Val.
castAs<DefinedOrUnknownSVal>();
2935 SValBuilder &svalBuilder =
C.getSValBuilder();
2937 DefinedOrUnknownSVal PtrEQ = svalBuilder.
evalEQ(
2938 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2941 const Expr *Arg1 = CE->
getArg(1);
2944 SVal TotalSize =
C.getSVal(Arg1);
2946 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2951 DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(
2952 State, TotalSize.
castAs<DefinedOrUnknownSVal>(),
2953 svalBuilder.makeIntValWithWidth(
2954 svalBuilder.getContext().getCanonicalSizeType(), 0));
2957 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2959 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2962 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2963 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2967 if (PrtIsNull && !SizeIsZero) {
2969 C,
Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
2974 if (PrtIsNull && SizeIsZero)
2979 bool IsKnownToBeAllocated =
false;
2988 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2993 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2996 MallocMemAux(
C,
Call, TotalSize, UnknownVal(), stateFree, Family);
3000 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
3001 if (ShouldFreeOnFail)
3002 Kind = OAR_FreeOnFailure;
3003 else if (!IsKnownToBeAllocated)
3004 Kind = OAR_DoNotTrackAfterFailure;
3008 SVal RetVal = stateRealloc->getSVal(CE,
C.getStackFrame());
3010 assert(FromPtr && ToPtr &&
3011 "By this point, FreeMemAux and MallocMemAux should have checked "
3012 "whether the argument or the return value is symbolic!");
3016 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
3017 ReallocPair(FromPtr, Kind));
3019 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
3020 return stateRealloc;
3026 const CallEvent &
Call,
3031 if (
Call.getNumArgs() < 2)
3034 SValBuilder &svalBuilder =
C.getSValBuilder();
3037 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
3039 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State,
3040 AllocationFamily(AF_Malloc));
3043MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
3045 CheckerContext &
C) {
3049 const ExplodedNode *AllocNode = N;
3050 const MemRegion *ReferenceRegion =
nullptr;
3054 if (!State->get<RegionState>(Sym))
3059 if (!ReferenceRegion) {
3060 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
3061 SVal Val = State->getSVal(MR);
3067 ReferenceRegion = MR;
3075 if (NSF == LeakStackFrame || NSF->
isParentOf(LeakStackFrame))
3080 return LeakInfo(AllocNode, ReferenceRegion);
3083void MallocChecker::HandleLeak(
SymbolRef Sym, ExplodedNode *N,
3084 CheckerContext &
C)
const {
3085 assert(N &&
"HandleLeak is only called with a non-null node");
3087 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3088 assert(RS &&
"cannot leak an untracked symbol");
3089 AllocationFamily Family = RS->getAllocationFamily();
3091 if (Family.Kind == AF_Alloca)
3094 const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);
3098 if (!Frontend || !Frontend->isEnabled())
3104 PathDiagnosticLocation LocUsedForUniqueing;
3105 const ExplodedNode *AllocNode =
nullptr;
3106 const MemRegion *Region =
nullptr;
3107 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
3112 AllocationStmt,
C.getSourceManager(), AllocNode->
getStackFrame());
3114 SmallString<200> buf;
3115 llvm::raw_svector_ostream os(buf);
3117 os <<
"Potential leak of memory pointed to by ";
3120 os <<
"Potential memory leak";
3123 auto R = std::make_unique<PathSensitiveBugReport>(
3124 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3126 R->markInteresting(Sym);
3127 R->addVisitor<MallocBugVisitor>(Sym,
true);
3128 if (ShouldRegisterNoOwnershipChangeVisitor)
3129 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
3130 C.emitReport(std::move(R));
3133void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3134 CheckerContext &
C)
const
3137 RegionStateTy OldRS = state->get<RegionState>();
3138 RegionStateTy::Factory &F = state->get_context<RegionState>();
3140 RegionStateTy RS = OldRS;
3141 SmallVector<SymbolRef, 2> Errors;
3142 for (
auto [Sym, State] : RS) {
3143 if (SymReaper.
isDead(Sym)) {
3144 if (State.isAllocated())
3145 Errors.push_back(Sym);
3147 RS = F.remove(RS, Sym);
3153 assert(state->get<ReallocPairs>() ==
3154 C.getState()->get<ReallocPairs>());
3155 assert(state->get<FreeReturnValue>() ==
3156 C.getState()->get<FreeReturnValue>());
3161 ReallocPairsTy RP = state->get<ReallocPairs>();
3162 for (
auto [Sym, ReallocPair] : RP) {
3163 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
3164 state = state->remove<ReallocPairs>(Sym);
3169 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3170 for (
auto [Sym, RetSym] : FR) {
3171 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
3172 state = state->remove<FreeReturnValue>(Sym);
3177 ExplodedNode *N =
C.getPredecessor();
3178 if (!Errors.empty()) {
3179 N =
C.generateNonFatalErrorNode(
C.getState());
3182 HandleLeak(Sym, N,
C);
3187 C.addTransition(state->set<RegionState>(RS), N);
3194 return Name ==
"unique_ptr" || Name ==
"shared_ptr";
3201 if (
const auto *TST = QT->
getAs<TemplateSpecializationType>()) {
3202 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
3225 llvm::SmallPtrSetImpl<const MemRegion *> *
Out;
3228 llvm::SmallPtrSetImpl<const MemRegion *> &
Out)
3241 C->getState()->getLValue(BaseDecl,
Reg->getAs<
SubRegion>(), IsVirtual);
3246 return std::nullopt;
3262 std::optional<FieldConsumer> FC = std::nullopt) {
3275 BaseSpec.getType()->getAsCXXRecordDecl()) {
3276 std::optional<FieldConsumer> NewFC;
3278 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());
3296 if (!
T->isRecordType() ||
T->isReferenceType())
3328 const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(
Call.getDecl());
3332 const auto *RD = CD->getParent();
3337 for (
const auto *Param : CD->parameters()) {
3338 QualType ParamType = Param->getType();
3353 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {
3370 for (
unsigned I = 0, E = std::min(
Call.getNumArgs(), CD->getNumParams());
3372 const Expr *ArgExpr =
Call.getArgExpr(I);
3376 QualType ParamType = CD->getParamDecl(I)->
getType();
3380 SVal ArgVal =
Call.getArgSVal(I);
3382 if (Sym && State->contains<RegionState>(Sym)) {
3383 const RefState *RS = State->get<RegionState>(Sym);
3384 if (RS && RS->isAllocated()) {
3385 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3401 return handleSmartPointerConstructorArguments(
Call, State);
3405 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;
3406 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3407 const Expr *AE =
Call.getArgExpr(I);
3416 SVal ArgVal =
Call.getArgSVal(I);
3417 const MemRegion *ArgRegion = ArgVal.
getAsRegion();
3420 SmartPtrFieldRoots);
3424 if (!SmartPtrFieldRoots.empty()) {
3425 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(
3426 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());
3427 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(
3428 SmartPtrFieldRootsVec, State);
3434void MallocChecker::checkPostCall(
const CallEvent &
Call,
3435 CheckerContext &
C)
const {
3437 if (
const auto *PostFN = PostFnMap.
lookup(
Call)) {
3438 (*PostFN)(
this,
C.getState(),
Call,
C);
3443 C.addTransition(handleSmartPointerRelatedCalls(
Call,
C,
C.getState()));
3446void MallocChecker::checkPreCall(
const CallEvent &
Call,
3447 CheckerContext &
C)
const {
3449 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3450 const CXXDeleteExpr *DE = DC->getOriginExpr();
3456 if (!NewDeleteChecker.isEnabled())
3464 bool IsKnownToBeAllocated;
3467 false, IsKnownToBeAllocated,
3468 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3470 C.addTransition(State);
3481 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3482 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3486 HandleDoubleFree(
C, SourceRange(),
true, Sym,
3494 if (
const auto *PreFN = PreFnMap.
lookup(
Call)) {
3495 (*PreFN)(
this,
C.getState(),
Call,
C);
3503 if (
const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&
Call)) {
3504 const FunctionDecl *FD = FC->getDecl();
3511 if (MallocChecker.isEnabled() && isFreeingCall(
Call))
3516 if (
const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&
Call)) {
3517 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3518 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3523 for (
unsigned I = 0, E =
Call.getNumArgs(); I != E; ++I) {
3524 SVal ArgSVal =
Call.getArgSVal(I);
3529 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3535void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3536 CheckerContext &
C)
const {
3537 checkEscapeOnReturn(S,
C);
3543void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3544 CheckerContext &
C)
const {
3545 checkEscapeOnReturn(S,
C);
3548void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3549 CheckerContext &
C)
const {
3558 SVal RetVal =
C.getSVal(E);
3565 if (
const SymbolicRegion *BMR =
3567 Sym = BMR->getSymbol();
3571 checkUseAfterFree(Sym,
C, E);
3577void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3578 CheckerContext &
C)
const {
3586 const BlockDataRegion *
R =
3589 auto ReferencedVars =
R->referenced_vars();
3590 if (ReferencedVars.empty())
3593 SmallVector<const MemRegion *, 10> Regions;
3594 MemRegionManager &MemMgr =
C.getSValBuilder().getRegionManager();
3596 for (
const auto &Var : ReferencedVars) {
3597 const VarRegion *VR = Var.getCapturedRegion();
3601 Regions.push_back(VR);
3605 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3606 C.addTransition(state);
3611 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3612 return (RS && RS->isReleased());
3615bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3616 const CallEvent &
Call, CheckerContext &
C)
const {
3617 if (
Call.getNumArgs() == 0)
3620 StringRef FunctionStr =
"";
3621 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3622 if (
const Stmt *Body = FD->
getBody())
3627 C.getSourceManager(),
C.getLangOpts());
3630 if (!FunctionStr.contains(
"__isl_"))
3636 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3637 if (
const RefState *RS = State->get<RegionState>(Sym))
3638 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3640 C.addTransition(State);
3644bool MallocChecker::checkUseAfterFree(
SymbolRef Sym, CheckerContext &
C,
3645 const Stmt *S)
const {
3655void MallocChecker::checkUseZeroAllocated(
SymbolRef Sym, CheckerContext &
C,
3656 const Stmt *S)
const {
3659 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3660 if (RS->isAllocatedOfSizeZero())
3661 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3663 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3669void MallocChecker::checkLocation(SVal l,
bool isLoad,
const Stmt *S,
3670 CheckerContext &
C)
const {
3673 checkUseAfterFree(Sym,
C, S);
3674 checkUseZeroAllocated(Sym,
C, S);
3682 bool Assumption)
const {
3683 RegionStateTy RS = state->get<RegionState>();
3684 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3686 ConstraintManager &CMgr = state->getConstraintManager();
3687 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3689 state = state->remove<RegionState>(Sym);
3694 ReallocPairsTy RP = state->get<ReallocPairs>();
3695 for (
auto [Sym, ReallocPair] : RP) {
3697 ConstraintManager &CMgr = state->getConstraintManager();
3698 ConditionTruthVal AllocFailed = CMgr.
isNull(state, Sym);
3702 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3703 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3704 if (RS->isReleased()) {
3705 switch (ReallocPair.Kind) {
3706 case OAR_ToBeFreedAfterFailure:
3707 state = state->set<RegionState>(ReallocSym,
3708 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3710 case OAR_DoNotTrackAfterFailure:
3711 state = state->remove<RegionState>(ReallocSym);
3714 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3718 state = state->remove<ReallocPairs>(Sym);
3724bool MallocChecker::ignoreDirectEscapeTo(
const CallEvent *
Call,
3727 EscapingSymbol =
nullptr;
3737 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(
Call)) {
3740 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3753 return !*FreeWhenDone;
3759 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3760 if (FirstSlot.ends_with(
"NoCopy"))
3767 if (FirstSlot.starts_with(
"addPointer") ||
3768 FirstSlot.starts_with(
"insertPointer") ||
3769 FirstSlot.starts_with(
"replacePointer") ||
3770 FirstSlot ==
"valueWithPointer") {
3777 if (Msg->getMethodFamily() ==
OMF_init) {
3778 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3793 if (!
Call->isInSystemHeader())
3800 StringRef FName = II->
getName();
3804 if (FName.ends_with(
"NoCopy")) {
3808 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3809 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3810 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3811 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3812 if (DeallocatorName ==
"kCFAllocatorNull")
3823 if (FName ==
"funopen")
3824 if (
Call->getNumArgs() >= 5 &&
Call->getArgSVal(4).isConstant(0))
3830 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3831 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3832 if (
Call->getNumArgs() >= 1) {
3834 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3835 if (
const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3836 if (D->getCanonicalDecl()->getName().contains(
"std"))
3846 if (FName ==
"CGBitmapContextCreate" ||
3847 FName ==
"CGBitmapContextCreateWithData" ||
3848 FName ==
"CVPixelBufferCreateWithBytes" ||
3849 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3850 FName ==
"OSAtomicEnqueue") {
3854 if (FName ==
"postEvent" &&
3859 if (FName ==
"connectImpl" &&
3864 if (FName ==
"singleShotImpl" &&
3874 if (FName ==
"GetOwnedMessageInternal") {
3882 if (
Call->argumentsMayEscape())
3892 const CallEvent *
Call,
3894 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3900 const CallEvent *
Call,
3903 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3908 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3909 RS->getAllocationFamily().Kind == AF_CXXNew);
3915 bool IsConstPointerEscape)
const {
3924 if (ignoreDirectEscapeTo(
Call, EscapingSymbol))
3929 if (EscapingSymbol && EscapingSymbol != sym)
3932 if (
const RefState *RS = State->get<RegionState>(sym))
3933 if (RS->isAllocated())
3935 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3940bool MallocChecker::isArgZERO_SIZE_PTR(
ProgramStateRef State, CheckerContext &
C,
3941 SVal ArgVal)
const {
3942 if (!KernelZeroSizePtrValue)
3943 KernelZeroSizePtrValue =
3946 const llvm::APSInt *ArgValKnown =
3947 C.getSValBuilder().getKnownValue(State, ArgVal);
3948 return ArgValKnown && *KernelZeroSizePtrValue &&
3949 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3954 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3955 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3957 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3959 if (!currMap.lookup(sym))
3969 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3970 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3971 N.contains_insensitive(
"intrusive") ||
3972 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3981 BugReporterContext &BRC,
3982 PathSensitiveBugReport &BR) {
3986 const RefState *RSCurr = state->get<RegionState>(Sym);
3987 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3992 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
4005 if (ReleaseFunctionSF && (ReleaseFunctionSF == CurrentSF ||
4007 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
4010 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
4011 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
4017 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
4020 if (
const auto *MD =
4022 const CXXRecordDecl *RD = MD->getParent();
4040 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
4041 SmallString<256> Buf;
4042 llvm::raw_svector_ostream
OS(Buf);
4045 if (isAllocated(RSCurr, RSPrev, S)) {
4046 Msg =
"Memory is allocated";
4047 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4048 Sym,
"Returned allocated memory");
4050 const auto Family = RSCurr->getAllocationFamily();
4051 switch (Family.Kind) {
4056 case AF_CXXNewArray:
4057 case AF_IfNameIndex:
4058 Msg =
"Memory is released";
4059 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4060 Sym,
"Returning; memory was released");
4062 case AF_InnerBuffer: {
4063 const MemRegion *ObjRegion =
4066 QualType ObjTy = TypedRegion->getValueType();
4067 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
4070 OS <<
"deallocated by call to destructor";
4071 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4072 Sym,
"Returning; inner buffer was deallocated");
4074 OS <<
"reallocated by call to '";
4075 const Stmt *S = RSCurr->getStmt();
4076 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
4077 OS << MemCallE->getMethodDecl()->getDeclName();
4078 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
4079 OS << OpCallE->getDirectCallee()->getDeclName();
4080 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
4082 CallEventRef<>
Call =
4084 if (
const auto *D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
4085 OS << D->getDeclName();
4090 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4091 Sym,
"Returning; inner buffer was reallocated");
4097 assert(
false &&
"Unhandled allocation family!");
4107 ReleaseFunctionSF = CurrentSF;
4111 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(SF.
getDecl())) {
4147 ReleaseFunctionSF = &SF;
4151 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
4152 Msg =
"Memory ownership is transferred";
4153 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
4154 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
4155 Mode = ReallocationFailed;
4156 Msg =
"Reallocation failed";
4157 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
4158 Sym,
"Reallocation failed");
4162 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
4163 "We only support one failed realloc at a time.");
4165 FailedReallocSymbol = sym;
4170 }
else if (Mode == ReallocationFailed) {
4171 assert(FailedReallocSymbol &&
"No symbol to look for.");
4174 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
4176 Msg =
"Attempt to reallocate memory";
4177 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4178 Sym,
"Returned reallocated memory");
4179 FailedReallocSymbol =
nullptr;
4192 PathDiagnosticLocation Pos;
4194 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
4198 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
4204 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
4209void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
4210 const char *NL,
const char *Sep)
const {
4212 RegionStateTy RS = State->get<RegionState>();
4214 if (!RS.isEmpty()) {
4215 Out << Sep <<
"MallocChecker :" << NL;
4216 for (
auto [Sym,
Data] : RS) {
4217 const RefState *RefS = State->get<RegionState>(Sym);
4218 AllocationFamily Family = RefS->getAllocationFamily();
4220 const CheckerFrontend *Frontend =
4221 getRelevantFrontendAs<CheckerFrontend>(Family);
4235namespace allocation_state {
4239 AllocationFamily Family(AF_InnerBuffer);
4240 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
4250 Mgr.
getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);
4258 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
4260 Chk->ShouldRegisterNoOwnershipChangeVisitor =
4262 DMMName,
"AddNoOwnershipChangeNotes");
4263 Chk->ModelAllocationFailure =
4265 DMMName,
"ModelAllocationFailure");
4268bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
4272#define REGISTER_CHECKER(NAME) \
4273 void ento::register##NAME(CheckerManager &Mgr) { \
4274 Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr); \
4277 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
4286#undef REGISTER_CHECKER
#define REGISTER_CHECKER(name)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
Result
Implement __builtin_bit_cast and related operations.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::Target Target
static bool isRvalueByValueRecordWithSmartPtr(const Expr *AE)
Check if an expression is an rvalue record with smart owning pointer fields passed by value.
static bool isFromStdNamespace(const CallEvent &Call)
static bool isStandardNew(const FunctionDecl *FD)
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
static QualType getDeepPointeeType(QualType T)
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)
Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.
static void collectSmartPtrFieldRegions(const MemRegion *Reg, QualType RecQT, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
Collect memory regions of smart owning pointer fields from a record type (including fields from base ...
static bool hasSmartPtrField(const CXXRecordDecl *CRD, std::optional< FieldConsumer > FC=std::nullopt)
Check if a record type has smart owning pointer fields (directly or in base classes).
static bool isStandardDelete(const FunctionDecl *FD)
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static bool isSmartPtrType(QualType QT)
static bool isStandardNewDelete(const T &FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
static bool isRvalueByValueRecord(const Expr *AE)
Check if an expression is an rvalue record type passed by value.
#define BUGTYPE_PROVIDER(NAME, DEF)
static bool isGRealloc(const CallEvent &Call)
static const Expr * getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD)
static bool isSmartPtrRecord(const CXXRecordDecl *RD)
Check if a CXXRecordDecl has a name matching recognized smart pointer names.
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)
Print expected name of a deallocator based on the allocator's family.
static bool isStandardRealloc(const CallEvent &Call)
static bool isSmartPtrCall(const CallEvent &Call)
Check if a call is a constructor of a smart owning pointer class that accepts pointer parameters.
static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)
Checks if the previous call to free on the given symbol failed - if free failed, returns true.
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)
Update the RefState to reflect the new memory allocation.
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
static bool isSmartPtrName(StringRef Name)
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
CanQualType getCanonicalSizeType() const
CanQualType UnsignedLongTy
static bool hasSameType(QualType T1, QualType T2)
Determine whether the given types T1 and T2 are equivalent.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
const BlockDecl * getBlockDecl() const
Represents a base class of a C++ class.
Represents binding an expression to a temporary.
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Represents a C++ constructor within a class.
Represents a delete expression for memory deallocation and destructor calls, e.g.
Represents a C++ destructor within a class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Represents a C++ struct/union/class.
Represents a C++ functional cast expression that builds a temporary object.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
static CharSourceRange getTokenRange(SourceRange R)
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
ASTContext & getASTContext() const LLVM_READONLY
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
SourceLocation getLocation() const
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Represents a member of a struct/union/class.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
ArrayRef< ParmVarDecl * > parameters() const
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
QualType getDeclaredReturnType() const
Get the declared return type, which may differ from the actual return type if the return type is dedu...
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Describes an C or C++ initializer list.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
An expression that sends a message to the given Objective-C object or class.
bool isConsumedExpr(Expr *E) const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
field_range fields() const
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
unsigned getNumArgs() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
bool isParentOf(const StackFrame *SF) const
const Decl * getDecl() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
The base class of all kinds of template declarations (e.g., class, function, etc.).
NamedDecl * getTemplatedDecl() const
Get the underlying, templated declaration.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isVoidPointerType() const
bool isFunctionPointerType() const
bool isPointerType() const
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
APSIntPtr getMaxValue(const llvm::APSInt &v)
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
ProgramStateManager & getStateManager() const
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
An immutable map from CallDescriptions to arbitrary data.
const T * lookup(const CallEvent &Call) const
CallEventRef getSimpleCall(const CallExpr *E, ProgramStateRef State, const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
Represents an abstract call to a function or method along a particular path.
Checker families (where a single backend class implements multiple related frontends) should derive f...
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
CheckerNameRef getName() const
const AnalyzerOptions & getAnalyzerOptions() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
const ProgramStateRef & getState() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
llvm::iterator_range< StackFrame::parent_iterator > stackframes() const
Iterates over the current stack frame and all of its ancestors.
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)
Top level wrappers for InstallAPI frontend operations.
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)
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