18 using namespace clang;
24 return isa<IntegerLiteral>(E) ||
25 isa<CharacterLiteral>(E) ||
26 isa<FloatingLiteral>(E) ||
27 isa<ObjCBoolLiteralExpr>(E) ||
28 isa<CXXBoolLiteralExpr>(E);
44 static bool shouldGenerateNote(llvm::raw_string_ostream &os,
45 const RefVal *PrevT,
const RefVal &CurrV,
48 RefVal PrevV = *PrevT;
53 assert(!PrevV.hasSameState(CurrV) &&
"The state should have changed.");
57 assert(CurrV.getCombinedCounts() == 0);
58 os <<
"Object released by directly sending the '-dealloc' message";
64 if (!PrevV.hasSameState(CurrV))
65 switch (CurrV.getKind()) {
68 if (PrevV.getCount() == CurrV.getCount()) {
70 if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
73 assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
74 os <<
"Object autoreleased";
78 if (PrevV.getCount() > CurrV.getCount())
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.";
89 if (CurrV.getIvarAccessHistory() ==
91 CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) {
92 os <<
"Strong instance variable relinquished. ";
94 os <<
"Object released.";
99 if (CurrV.getAutoreleaseCount())
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";
126 for (
unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++)
127 if (
const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion())
128 if (
const auto *TR = dyn_cast<TypedValueRegion>(MR))
129 if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymExpr() == Sym)
139 llvm::raw_string_ostream &os) {
141 if (
const CallExpr *CE = dyn_cast<CallExpr>(S)) {
144 SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
151 if (
const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
156 os <<
"function call";
158 }
else if (isa<CXXNewExpr>(S)) {
159 os <<
"Operator 'new'";
161 assert(isa<ObjCMessageExpr>(S));
165 switch (Call->getMessageKind()) {
179 auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);
189 os <<
"a Core Foundation object of type '" 200 if (!isa<ObjCObjectPointerType>(T)) {
201 os <<
"an Objective-C object with a ";
209 if (CurrV.isOwned()) {
210 os <<
"+1 retain count";
212 assert(CurrV.isNotOwned());
213 os <<
"+0 retain count";
217 os <<
" into an out parameter '";
218 const ParmVarDecl *PVD = (*CE)->parameters()[*Idx];
223 QualType RT = (*CE)->getResultType();
225 SVal RV = (*CE)->getReturnValue();
226 if (CurrSt->isNull(RV).isConstrainedTrue()) {
227 os <<
" (assuming the call returns zero)";
228 }
else if (CurrSt->isNonNull(RV).isConstrainedTrue()) {
229 os <<
" (assuming the call returns non-zero)";
245 RefCountReportVisitor(
SymbolRef sym) : Sym(sym) {}
247 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
253 std::shared_ptr<PathDiagnosticPiece> VisitNode(
const ExplodedNode *N,
262 class RefLeakReportVisitor :
public RefCountReportVisitor {
264 RefLeakReportVisitor(
SymbolRef sym) : RefCountReportVisitor(sym) {}
296 static std::shared_ptr<PathDiagnosticEventPiece>
309 llvm::raw_string_ostream os(sbuf);
311 for (
unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) {
314 if (!PVD->
hasAttr<OSConsumedAttr>())
317 if (
SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) {
321 if (!CountBeforeCall || !CountAtExit)
324 unsigned CountBefore = CountBeforeCall->
getCount();
325 unsigned CountAfter = CountAtExit->getCount();
327 bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1;
332 os <<
"' is marked as consuming, but the function did not consume " 333 <<
"the reference\n";
338 if (os.str().empty())
347 Call->getRuntimeDefinition().getDecl()->getSourceRange().getEnd(),
SM);
350 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
353 std::shared_ptr<PathDiagnosticPiece>
360 if (
auto PD = annotateConsumedSummaryMismatch(N, *CE, SM, CEMgr))
375 if (!CurrT)
return nullptr;
377 const RefVal &CurrV = *CurrT;
383 llvm::raw_string_ostream os(sbuf);
390 if (isa<ObjCIvarRefExpr>(S) &&
395 if (isa<ObjCArrayLiteral>(S)) {
396 os <<
"NSArray literal is an object with a +0 retain count";
397 }
else if (isa<ObjCDictionaryLiteral>(S)) {
398 os <<
"NSDictionary literal is an object with a +0 retain count";
399 }
else if (
const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
401 os <<
"NSNumber literal is an object with a +0 retain count";
405 BoxClass = Method->getClassInterface();
410 os << *BoxClass <<
" b";
415 os <<
"oxed expression produces an object with a +0 retain count";
417 }
else if (isa<ObjCIvarRefExpr>(S)) {
418 os <<
"Object loaded from instance variable";
420 generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os);
424 return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
429 bool DeallocSent =
false;
438 if (
const CallExpr *CE = dyn_cast<CallExpr>(S)) {
443 for (
auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) {
447 if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
454 if (
const Expr *receiver = ME->getInstanceReceiver()) {
455 if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
456 .getAsLocSymbol() == Sym) {
464 if (!shouldGenerateNote(os, PrevT, CurrV, DeallocSent))
467 if (os.str().empty())
473 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
478 if (
const Expr *Exp = dyn_cast_or_null<Expr>(Child))
479 if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
480 P->addRange(Exp->getSourceRange());
488 if (
const auto *VR = dyn_cast_or_null<VarRegion>(MR))
489 return std::string(VR->getDecl()->getName());
501 struct AllocationInfo {
508 N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {}
515 const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
552 if (NContext == LeakContext || NContext->
isParentOf(LeakContext))
553 AllocationNodeInCurrentOrParentContext = N;
557 if (!InitMethodContext)
559 const Stmt *CE = CEP->getCallExpr();
560 if (
const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
561 const Stmt *RecExpr = ME->getInstanceReceiver();
563 SVal RecV = St->getSVal(RecExpr, NContext);
565 InitMethodContext = CEP->getCalleeContext();
576 if (InitMethodContext) {
581 InterestingMethodContext = InitMethodContext;
586 assert(N &&
"Could not find allocation node");
588 if (AllocationNodeInCurrentOrParentContext &&
591 FirstBinding =
nullptr;
593 return AllocationInfo(AllocationNodeInCurrentOrParentContext,
595 InterestingMethodContext);
598 std::shared_ptr<PathDiagnosticPiece>
602 return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
605 std::shared_ptr<PathDiagnosticPiece>
616 AllocationInfo AllocI = GetAllocationSite(BRC.
getStateManager(), EndN, Sym);
618 const MemRegion* FirstBinding = AllocI.R;
630 llvm::raw_string_ostream os(sbuf);
632 os <<
"Object leaked: ";
635 if (RegionDescription) {
636 os <<
"object allocated and stored into '" << *RegionDescription <<
'\'';
652 os << (isa<ObjCMethodDecl>(D) ?
" is returned from a method " 653 :
" is returned from a function ");
655 if (D->
hasAttr<CFReturnsNotRetainedAttr>()) {
656 os <<
"that is annotated as CF_RETURNS_NOT_RETAINED";
657 }
else if (D->
hasAttr<NSReturnsNotRetainedAttr>()) {
658 os <<
"that is annotated as NS_RETURNS_NOT_RETAINED";
659 }
else if (D->
hasAttr<OSReturnsNotRetainedAttr>()) {
660 os <<
"that is annotated as OS_RETURNS_NOT_RETAINED";
664 os <<
"managed by Automatic Reference Counting";
666 os <<
"whose name ('" << MD->getSelector().getAsString()
667 <<
"') does not start with " 668 "'copy', 'mutableCopy', 'alloc' or 'new'." 669 " This violates the naming convention rules" 670 " given in the Memory Management Guide for Cocoa";
674 os <<
"whose name ('" << *FD
675 <<
"') does not contain 'Copy' or 'Create'. This violates the naming" 676 " convention rules given in the Memory Management Guide for Core" 681 os <<
" is not referenced later in this execution path and has a retain " 682 "count of +" << RV->getCount();
685 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
690 bool registerVisitor)
691 :
BugReport(D, D.getDescription(), n), Sym(sym) {
693 addVisitor(llvm::make_unique<RefCountReportVisitor>(sym));
699 :
BugReport(D, D.getDescription(), endText, n) {
701 addVisitor(llvm::make_unique<RefCountReportVisitor>(sym));
712 const Decl *PDecl = Region->getDecl();
713 if (PDecl && isa<ParmVarDecl>(PDecl)) {
716 Location = ParamLocation;
717 UniqueingLocation = ParamLocation;
737 AllocationInfo AllocI =
740 AllocNode = AllocI.N;
741 AllocBinding = AllocI.R;
742 markInteresting(AllocI.InterestingMethodContext);
751 AllocBinding =
nullptr;
757 AllocNode->getLocationContext());
758 Location = AllocLocation;
762 UniqueingLocation = AllocLocation;
763 UniqueingDecl = AllocNode->getLocationContext()->getDecl();
767 assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
769 llvm::raw_string_ostream os(Description);
770 os <<
"Potential leak of an object";
773 if (RegionDescription) {
774 os <<
" stored into '" << *RegionDescription <<
'\'';
785 : RefCountReport(D, LOpts, n, sym,
false) {
787 deriveAllocLocation(Ctx, sym);
789 deriveParamLocation(Ctx, sym);
791 createDescription(Ctx);
793 addVisitor(llvm::make_unique<RefLeakReportVisitor>(sym));
Indicates that the tracked object is a generalized object.
Indicates that the tracked object is a CF object.
Represents a function declaration or definition.
static constexpr const char * DeallocTagDescription
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
ASTContext & getASTContext()
RefLeakReport(RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n, SymbolRef sym, CheckerContext &Ctx)
Stmt - This represents one statement.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Decl - This represents one declaration (or definition), e.g.
Represents a point when we begin processing an inlined call.
Manages the lifetime of CallEvent objects.
const ProgramStateRef & getState() const
const T * getAs() const
Member-template getAs<specific type>'.
const Decl & getCodeDecl() const
ObjCMethodDecl - Represents an instance or class method declaration.
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
Represents a parameter to a function.
unsigned getCount() const
bool isParentOf(const LocationContext *LC) const
RefCountReport(RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n, SymbolRef sym, bool registerVisitor=true)
const MemRegion * getRegion()
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Optional< T > getLocationAs() const LLVM_LVALUE_FUNCTION
Represents a point when we start the call exit sequence (for inlined call).
ProgramStateManager & getStateManager()
const LocationContext * getLocationContext() const
const clang::PrintingPolicy & getPrintingPolicy() const
const LocationContext * getParent() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
ExplodedNode * getFirstPred()
Represents an ObjC class declaration.
const MemSpaceRegion * getMemorySpace() const
static std::string getPrettyTypeName(QualType QT)
If type represents a pointer to CXXRecordDecl, and is not a typedef, return the decl name...
virtual QualType getType() const =0
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
const Stmt * getCallSite() const
bool isSynthesizedAccessor(const StackFrameContext *SFC)
Returns true if this stack frame is for an Objective-C method that is a property getter or setter who...
This represents one expression.
CallEventRef getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State)
Gets an outside caller given a callee context.
virtual StringRef getTagDescription() const =0
bool inTopFrame() const override
Return true if the current LocationContext has no caller context.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
An expression that sends a message to the given Objective-C object or class.
void markInteresting(SymbolRef sym)
CallEventRef< ObjCMethodCall > getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State, const LocationContext *LCtx)
bool isNull() const
Return true if this QualType doesn't point to a type yet.
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type...
Indicates that the tracked object is an Objective-C object.
CallEventManager & getCallEventManager()
ASTContext & getASTContext() const LLVM_READONLY
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
ObjCBoxedExpr - used for generalized expression boxing.
const ReturnStmt * getReturnStmt() const
CallEventRef getCall(const Stmt *S, ProgramStateRef State, const LocationContext *LC)
Gets a call event for a function call, Objective-C method call, or a 'new' call.
Dataflow Directional Tag Classes.
virtual void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const
Appends a human-readable name for this declaration into the given stream.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
const ProgramPointTag * getTag() const
const Decl * getDecl() const
Represents a pointer to an Objective C object.
const FunctionDecl * getAsFunctionDecl() const
getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a CodeTextRegion wrapping a FunctionDecl...
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
ProgramStateManager & getStateManager()
const RefVal * getRefBinding(ProgramStateRef State, SymbolRef Sym)
const StackFrameContext * getStackFrame() const
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
SourceManager & getSourceManager()
static PathDiagnosticLocation createEndOfPath(const ExplodedNode *N, const SourceManager &SM)
Create a location corresponding to the next valid ExplodedNode as end of path location.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
std::string getQualifiedNameAsString() const
void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler &F)
const StackFrameContext * getStackFrame() const
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
This class provides an interface through which checkers can create individual bug reports...
const LocationContext * getLocationContext() const
const LangOptions & getLangOpts() const
This class handles loading and caching of source files into memory.
SourceManager & getSourceManager()
static bool isNumericLiteralExpression(const Expr *E)
QualType getPointeeType() const
Gets the type pointed to by this ObjC pointer.