16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/SmallVector.h"
37 return std::string(RD->getName());
53 assert(!PrevV.
hasSameState(CurrV) &&
"The state should have changed.");
58 os <<
"Object released by directly sending the '-dealloc' message";
74 os <<
"Object autoreleased";
79 os <<
"Reference count decremented.";
81 os <<
"Reference count incremented.";
83 if (
unsigned Count = CurrV.
getCount())
84 os <<
" The object now has a +" << Count <<
" retain count.";
90 RefVal::IvarAccessHistory::ReleasedAfterDirectAccess &&
92 os <<
"Strong instance variable relinquished. ";
94 os <<
"Object released.";
102 os <<
"Object returned to caller as an owning reference (single "
103 "retain count transferred to caller)";
107 os <<
"Object returned to caller with a +0 retain count";
119static std::optional<unsigned>
125 for (
unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++)
126 if (
const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion())
127 if (
const auto *TR = dyn_cast<TypedValueRegion>(MR))
128 if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymbol() == Sym)
135 if (
const auto *ME = dyn_cast<MemberExpr>(Callee)) {
136 if (ME->getMemberDecl()->getNameAsString() !=
"alloc")
138 const Expr *
This = ME->getBase()->IgnoreParenImpCasts();
139 if (
const auto *DRE = dyn_cast<DeclRefExpr>(
This)) {
144 if (
const auto *RD = dyn_cast<CXXRecordDecl>(VD->
getDeclContext()))
153 if (
const auto *CE = dyn_cast<CallExpr>(S))
163 llvm::raw_string_ostream &os) {
165 if (
const CallExpr *CE = dyn_cast<CallExpr>(S)) {
168 SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), SF);
173 FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
175 if (
const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
176 os <<
"Call to method '" << MD->getQualifiedNameAsString() <<
'\'';
180 os <<
"function call";
183 os <<
"Operator 'new'";
189 switch (
Call->getMessageKind()) {
202 std::optional<CallEventRef<>> CE = Mgr.
getCall(S, CurrSt, SF, {
nullptr, 0});
213 os <<
"a Core Foundation object of type '" << Sym->
getType() <<
"' with a ";
214 }
else if (CurrV.
getObjKind() == ObjKind::OS) {
217 }
else if (CurrV.
getObjKind() == ObjKind::Generalized) {
218 os <<
"an object of type '" << Sym->
getType() <<
"' with a ";
223 os <<
"an Objective-C object with a ";
231 os <<
"+1 retain count";
234 os <<
"+0 retain count";
238 os <<
" into an out parameter '";
239 const ParmVarDecl *PVD = (*CE)->parameters()[*Idx];
244 QualType RT = (*CE)->getResultType();
246 SVal RV = (*CE)->getReturnValue();
247 if (CurrSt->isNull(RV).isConstrainedTrue()) {
248 os <<
" (assuming the call returns zero)";
249 }
else if (CurrSt->isNonNull(RV).isConstrainedTrue()) {
250 os <<
" (assuming the call returns non-zero)";
270 void Profile(llvm::FoldingSetNodeID &ID)
const override {
289 LastBinding(LastBinding) {}
324static std::shared_ptr<PathDiagnosticEventPiece>
337 llvm::raw_string_ostream os(sbuf);
339 for (
unsigned I=0; I <
Call->getNumArgs() && I < Parameters.size(); ++I) {
342 if (!PVD->
hasAttr<OSConsumedAttr>())
349 if (!CountBeforeCall || !CountAtExit)
352 unsigned CountBefore = CountBeforeCall->
getCount();
353 unsigned CountAfter = CountAtExit->
getCount();
355 bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1;
360 os <<
"' is marked as consuming, but the function did not consume "
361 <<
"the reference\n";
370 return std::make_shared<PathDiagnosticEventPiece>(L, sbuf);
374static std::shared_ptr<PathDiagnosticEventPiece>
393 llvm::raw_string_ostream os(
s);
394 os <<
"Parameter '" << PVD->getDeclName() <<
"' starts at +";
396 os <<
"1, as it is marked as consuming";
401 return std::make_shared<PathDiagnosticEventPiece>(L,
s);
431 const RefVal &CurrV = *CurrT;
437 llvm::raw_string_ostream os(sbuf);
440 os <<
"Object is now not exclusively owned";
442 return std::make_shared<PathDiagnosticEventPiece>(Pos, sbuf);
455 os <<
"NSArray literal is an object with a +0 retain count";
457 os <<
"NSDictionary literal is an object with a +0 retain count";
458 }
else if (
const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
460 os <<
"NSNumber literal is an object with a +0 retain count";
464 BoxClass =
Method->getClassInterface();
469 os << *BoxClass <<
" b";
474 os <<
"oxed expression produces an object with a +0 retain count";
477 os <<
"Object loaded from instance variable";
483 return std::make_shared<PathDiagnosticEventPiece>(Pos, sbuf);
488 bool DeallocSent =
false;
493 os <<
"Assuming dynamic cast returns null due to type mismatch";
501 if (
const CallExpr *CE = dyn_cast<CallExpr>(S)) {
506 for (
auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) {
510 if (CurrSt->getSValAsScalarOrLoc(*AI, SF).getAsLocSymbol() !=
Sym)
517 if (
const Expr *R = ME->getInstanceReceiver()) {
518 if (CurrSt->getSValAsScalarOrLoc(R, SF).getAsLocSymbol() ==
Sym) {
534 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, sbuf);
539 if (
const Expr *Exp = dyn_cast_or_null<Expr>(Child))
540 if (CurrSt->getSValAsScalarOrLoc(Exp, SF).getAsLocSymbol() ==
Sym) {
541 P->addRange(Exp->getSourceRange());
549 if (
const auto *VR = dyn_cast_or_null<VarRegion>(MR))
550 return std::string(VR->getDecl()->getName());
565 : Sym(Sym),
Result(ToFill) {}
570 if (!SymV || SymV != Sym)
574 Result.emplace_back(R, Val);
585 VarBindingsCollector Collector{Sym,
Result};
586 while (
Result.empty() && Node) {
600struct AllocationInfo {
601 const ExplodedNode* N;
603 const StackFrame *InterestingMethodStackFrame;
604 AllocationInfo(
const ExplodedNode *InN,
const MemRegion *InR,
605 const StackFrame *InterestingMethodStackFrame)
607 InterestingMethodStackFrame(InterestingMethodStackFrame) {}
614 const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
620 const StackFrame *InitMethodStackFrame =
nullptr;
637 if (MR->getStackFrame() == LeakStackFrame)
651 if (NStackFrame == LeakStackFrame ||
653 AllocationNodeInCurrentOrParentContext = N;
657 if (!InitMethodStackFrame)
659 const Stmt *CE = CEP->getCallExpr();
660 if (
const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
661 if (
const Expr *RecExpr = ME->getInstanceReceiver()) {
662 SVal RecV = St->getSVal(RecExpr, NStackFrame);
664 InitMethodStackFrame = CEP->getCalleeStackFrame();
674 const StackFrame *InterestingMethodStackFrame =
nullptr;
675 if (InitMethodStackFrame) {
680 InterestingMethodStackFrame = InitMethodStackFrame;
685 assert(N &&
"Could not find allocation node");
687 if (AllocationNodeInCurrentOrParentContext &&
688 AllocationNodeInCurrentOrParentContext->
getStackFrame() != LeakStackFrame)
689 FirstBinding =
nullptr;
691 return AllocationInfo(AllocationNodeInCurrentOrParentContext, FirstBinding,
692 InterestingMethodStackFrame);
715 llvm::raw_string_ostream os(sbuf);
717 os <<
"Object leaked: ";
719 std::optional<std::string> RegionDescription =
describeRegion(LastBinding);
720 if (RegionDescription) {
721 os <<
"object allocated and stored into '" << *RegionDescription <<
'\'';
734 os << (isa<ObjCMethodDecl>(D) ?
" is returned from a method "
735 :
" is returned from a function ");
737 if (D->
hasAttr<CFReturnsNotRetainedAttr>()) {
738 os <<
"that is annotated as CF_RETURNS_NOT_RETAINED";
739 }
else if (D->
hasAttr<NSReturnsNotRetainedAttr>()) {
740 os <<
"that is annotated as NS_RETURNS_NOT_RETAINED";
741 }
else if (D->
hasAttr<OSReturnsNotRetainedAttr>()) {
742 os <<
"that is annotated as OS_RETURNS_NOT_RETAINED";
746 os <<
"managed by Automatic Reference Counting";
748 os <<
"whose name ('" << MD->getSelector().getAsString()
749 <<
"') does not start with "
750 "'copy', 'mutableCopy', 'alloc' or 'new'."
751 " This violates the naming convention rules"
752 " given in the Memory Management Guide for Cocoa";
758 os <<
"whose name ('" << *FD
759 <<
"') does not contain 'Copy' or 'Create'. This violates the "
760 "naming convention rules given in the Memory Management Guide "
761 "for Core Foundation";
764 os <<
"whose name ('" << FuncName <<
"') starts with '"
765 << StringRef(FuncName).substr(0, 3) <<
"'";
770 os <<
" is not referenced later in this execution path and has a retain "
775 return std::make_shared<PathDiagnosticEventPiece>(L, sbuf);
780 bool IsReleaseUnowned)
803 const Decl *PDecl = Region->getDecl();
804 if (isa_and_nonnull<ParmVarDecl>(PDecl)) {
807 Location = ParamLocation;
827 AllocationInfo AllocI =
830 AllocNode = AllocI.N;
831 AllocFirstBinding = AllocI.R;
841 AllocFirstBinding =
nullptr;
847 Location = AllocLocation;
855void RefLeakReport::createDescription(CheckerContext &Ctx) {
859 os <<
"Potential leak of an object";
861 std::optional<std::string> RegionDescription =
863 if (RegionDescription) {
864 os <<
" stored into '" << *RegionDescription <<
'\'';
872void RefLeakReport::findBindingToReport(CheckerContext &Ctx,
873 ExplodedNode *Node) {
874 if (!AllocFirstBinding)
880 if (Node->
getState()->getSVal(AllocFirstBinding).getAsSymbol() ==
Sym) {
882 AllocBindingToReport = AllocFirstBinding;
905 if (!AllVarBindings.empty() &&
906 !llvm::is_contained(llvm::make_first_range(AllVarBindings),
907 AllocFirstBinding)) {
909 AllocBindingToReport = AllVarBindings[0].first;
921 AllocBindingToReport, *
this);
923 AllocBindingToReport = AllocFirstBinding;
932 deriveAllocLocation(Ctx);
933 findBindingToReport(Ctx, N);
935 if (!AllocFirstBinding)
936 deriveParamLocation(Ctx);
938 createDescription(Ctx);
static const MemRegion * getRegion(const CallEvent &Call, const MutexDescriptor &Descriptor, bool IsLock)
Result
Implement __builtin_bit_cast and related operations.
static std::shared_ptr< PathDiagnosticEventPiece > annotateStartParameter(const ExplodedNode *N, SymbolRef Sym, const SourceManager &SM)
Annotate the parameter at the analysis entry point.
static std::string getPrettyTypeName(QualType QT)
If type represents a pointer to CXXRecordDecl, and is not a typedef, return the decl name.
static bool shouldGenerateNote(llvm::raw_string_ostream &os, const RefVal *PrevT, const RefVal &CurrV, bool DeallocSent)
Write information about the type state change to os, return whether the note should be generated.
static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt, const StackFrame *SF, const RefVal &CurrV, SymbolRef &Sym, const Stmt *S, llvm::raw_string_ostream &os)
static std::optional< unsigned > findArgIdxOfSymbol(ProgramStateRef CurrSt, const StackFrame *SF, SymbolRef &Sym, std::optional< CallEventRef<> > CE)
Finds argument index of the out paramter in the call S corresponding to the symbol Sym.
static bool isNumericLiteralExpression(const Expr *E)
static std::shared_ptr< PathDiagnosticEventPiece > annotateConsumedSummaryMismatch(const ExplodedNode *N, CallExitBegin &CallExitLoc, const SourceManager &SM, CallEventManager &CEMgr)
Insert a diagnostic piece at function exit if a function parameter is annotated as "os_consumed",...
llvm::SmallVector< std::pair< const MemRegion *, SVal >, 4 > Bindings
static std::string findAllocatedObjectName(const Stmt *S, QualType QT)
static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr, const ExplodedNode *N, SymbolRef Sym)
static std::optional< std::string > describeRegion(const MemRegion *MR)
static std::optional< std::string > findMetaClassAlloc(const Expr *Callee)
static const ExplodedNode * getCalleeNode(const ExplodedNode *Pred)
Find the first node with the parent stack frame.
static Bindings getAllVarBindingsForSymbol(ProgramStateManager &Manager, const ExplodedNode *Node, SymbolRef Sym)
__device__ __2f16 float __ockl_bool s
a trap message and trap category.
const LangOptions & getLangOpts() const
const clang::PrintingPolicy & getPrintingPolicy() const
Represents a single basic block in a source-level CFG.
A boolean literal, per ([C++ lex.bool] Boolean literals).
Represents a point when we begin processing an inlined call.
Represents a point when we start the call exit sequence (for inlined call).
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
DeclContext * getDeclContext()
This represents one expression.
Represents a function declaration or definition.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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...
virtual void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const
Appends a human-readable name for this declaration into the given stream.
ObjCBoolLiteralExpr - Objective-C Boolean Literal.
ObjCBoxedExpr - used for generalized expression boxing.
Represents an ObjC class declaration.
An expression that sends a message to the given Objective-C object or class.
ObjCMethodDecl - Represents an instance or class method declaration.
Represents a pointer to an Objective C object.
QualType getPointeeType() const
Gets the type pointed to by this ObjC pointer.
Represents a parameter to a function.
ProgramPoints can be "tagged" as representing points specific to a given analysis entity.
const ProgramPointTag * getTag() const
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type.
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.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
This class handles loading and caching of source files into memory.
It represents a stack frame of the call stack.
bool isParentOf(const StackFrame *SF) const
const Expr * getCallSite() const
const Decl * getDecl() const
const StackFrame * getParent() const
It might return null.
Stmt - This represents one statement.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
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>'.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
ASTContext & getASTContext() const
ProgramStateManager & getStateManager() const
const SourceManager & getSourceManager() const
BugReporterVisitor()=default
static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, const PathSensitiveBugReport &BR)
Generates the default final diagnostic piece.
Manages the lifetime of CallEvent objects.
CallEventRef getCaller(const StackFrame *CalleeSF, ProgramStateRef State)
Gets an outside caller given a callee context.
CallEventRef< ObjCMethodCall > getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State, const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
CallEventRef getCall(const Stmt *S, ProgramStateRef State, const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
Gets a call event for a function call, Objective-C method call, a 'new', or a 'delete' call.
const SourceManager & getSourceManager()
ProgramStateManager & getStateManager()
const StackFrame * getStackFrame() const
const ProgramStateRef & getState() const
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.
std::optional< T > getLocationAs() const &
ExplodedNode * getFirstPred()
const Decl & getCodeDecl() const
const StackFrame * getStackFrame() const
MemRegion - The root abstract class for all memory regions.
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 UniqueingLocation
Reports with different uniqueing locations are considered to be different for the purposes of dedupli...
const ExplodedNode * getErrorNode() const
PathSensitiveBugReport(const BugType &bt, StringRef desc, const ExplodedNode *errorNode)
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
const Decl * UniqueingDecl
CallEventManager & getCallEventManager()
void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler &F)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
const MemRegion * getRegion()
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
virtual QualType getType() const =0
void Profile(llvm::FoldingSetNodeID &ID) const override
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR) override
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
RefCountReportVisitor(SymbolRef S, bool IRU)
RefCountReport(const RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n, SymbolRef sym, bool isLeak=false, bool IsReleaseUnowned=false)
RefLeakReportVisitor(SymbolRef Sym, const MemRegion *LastBinding)
PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR) override
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
RefLeakReport(const RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n, SymbolRef sym, CheckerContext &Ctx)
unsigned getCount() const
unsigned getCombinedCounts() const
IvarAccessHistory getIvarAccessHistory() const
Returns what the analyzer knows about direct accesses to a particular instance variable.
unsigned getAutoreleaseCount() const
bool hasSameState(const RefVal &X) const
ObjKind getObjKind() const
static const SimpleProgramPointTag & getCastFailTag()
static const SimpleProgramPointTag & getDeallocSentTag()
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrame *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
bool isSynthesizedAccessor(const StackFrame *SF)
Returns true if this stack frame is for an Objective-C method that is a property getter or setter who...
const RefVal * getRefBinding(ProgramStateRef State, SymbolRef Sym)
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
ObjKind
Determines the object kind of a tracked object.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
@ CF
Indicates that the tracked object is a CF object.
@ ObjC
Indicates that the tracked object is an Objective-C object.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)