10b57cec5SDimitry Andric //==--- RetainCountChecker.h - Checks for leaks and other issues -*- C++ -*--// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines the methods for RetainCountChecker, which implements 100b57cec5SDimitry Andric // a reference count checker for Core Foundation and Cocoa on (Mac OS X). 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_H 150b57cec5SDimitry Andric #define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_H 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 180b57cec5SDimitry Andric #include "RetainCountDiagnostics.h" 190b57cec5SDimitry Andric #include "clang/AST/Attr.h" 200b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h" 210b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h" 220b57cec5SDimitry Andric #include "clang/AST/ParentMap.h" 230b57cec5SDimitry Andric #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 24a7dea167SDimitry Andric #include "clang/Analysis/PathDiagnostic.h" 250b57cec5SDimitry Andric #include "clang/Analysis/RetainSummaryManager.h" 260b57cec5SDimitry Andric #include "clang/Basic/LangOptions.h" 270b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 280b57cec5SDimitry Andric #include "clang/Analysis/SelectorExtras.h" 290b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 300b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 310b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 320b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 330b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 340b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 350b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 360b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 370b57cec5SDimitry Andric #include "llvm/ADT/FoldingSet.h" 380b57cec5SDimitry Andric #include "llvm/ADT/ImmutableList.h" 390b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 400b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 410b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 420b57cec5SDimitry Andric #include <cstdarg> 430b57cec5SDimitry Andric #include <utility> 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric namespace clang { 460b57cec5SDimitry Andric namespace ento { 470b57cec5SDimitry Andric namespace retaincountchecker { 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric /// Metadata on reference. 500b57cec5SDimitry Andric class RefVal { 510b57cec5SDimitry Andric public: 520b57cec5SDimitry Andric enum Kind { 530b57cec5SDimitry Andric Owned = 0, // Owning reference. 540b57cec5SDimitry Andric NotOwned, // Reference is not owned by still valid (not freed). 550b57cec5SDimitry Andric Released, // Object has been released. 560b57cec5SDimitry Andric ReturnedOwned, // Returned object passes ownership to caller. 570b57cec5SDimitry Andric ReturnedNotOwned, // Return object does not pass ownership to caller. 580b57cec5SDimitry Andric ERROR_START, 590b57cec5SDimitry Andric ErrorDeallocNotOwned, // -dealloc called on non-owned object. 600b57cec5SDimitry Andric ErrorUseAfterRelease, // Object used after released. 610b57cec5SDimitry Andric ErrorReleaseNotOwned, // Release of an object that was not owned. 620b57cec5SDimitry Andric ERROR_LEAK_START, 630b57cec5SDimitry Andric ErrorLeak, // A memory leak due to excessive reference counts. 640b57cec5SDimitry Andric ErrorLeakReturned, // A memory leak due to the returning method not having 650b57cec5SDimitry Andric // the correct naming conventions. 660b57cec5SDimitry Andric ErrorOverAutorelease, 670b57cec5SDimitry Andric ErrorReturnedNotOwned 680b57cec5SDimitry Andric }; 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric /// Tracks how an object referenced by an ivar has been used. 710b57cec5SDimitry Andric /// 720b57cec5SDimitry Andric /// This accounts for us not knowing if an arbitrary ivar is supposed to be 730b57cec5SDimitry Andric /// stored at +0 or +1. 740b57cec5SDimitry Andric enum class IvarAccessHistory { 750b57cec5SDimitry Andric None, 760b57cec5SDimitry Andric AccessedDirectly, 770b57cec5SDimitry Andric ReleasedAfterDirectAccess 780b57cec5SDimitry Andric }; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric private: 810b57cec5SDimitry Andric /// The number of outstanding retains. 820b57cec5SDimitry Andric unsigned Cnt; 830b57cec5SDimitry Andric /// The number of outstanding autoreleases. 840b57cec5SDimitry Andric unsigned ACnt; 850b57cec5SDimitry Andric /// The (static) type of the object at the time we started tracking it. 860b57cec5SDimitry Andric QualType T; 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric /// The current state of the object. 890b57cec5SDimitry Andric /// 900b57cec5SDimitry Andric /// See the RefVal::Kind enum for possible values. 910b57cec5SDimitry Andric unsigned RawKind : 5; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric /// The kind of object being tracked (CF or ObjC or OSObject), if known. 940b57cec5SDimitry Andric /// 950b57cec5SDimitry Andric /// See the ObjKind enum for possible values. 960b57cec5SDimitry Andric unsigned RawObjectKind : 3; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric /// True if the current state and/or retain count may turn out to not be the 990b57cec5SDimitry Andric /// best possible approximation of the reference counting state. 1000b57cec5SDimitry Andric /// 1010b57cec5SDimitry Andric /// If true, the checker may decide to throw away ("override") this state 1020b57cec5SDimitry Andric /// in favor of something else when it sees the object being used in new ways. 1030b57cec5SDimitry Andric /// 1040b57cec5SDimitry Andric /// This setting should not be propagated to state derived from this state. 1050b57cec5SDimitry Andric /// Once we start deriving new states, it would be inconsistent to override 1060b57cec5SDimitry Andric /// them. 1070b57cec5SDimitry Andric unsigned RawIvarAccessHistory : 2; 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric RefVal(Kind k, ObjKind o, unsigned cnt, unsigned acnt, QualType t, 1100b57cec5SDimitry Andric IvarAccessHistory IvarAccess) 1110b57cec5SDimitry Andric : Cnt(cnt), ACnt(acnt), T(t), RawKind(static_cast<unsigned>(k)), 1120b57cec5SDimitry Andric RawObjectKind(static_cast<unsigned>(o)), 1130b57cec5SDimitry Andric RawIvarAccessHistory(static_cast<unsigned>(IvarAccess)) { 1140b57cec5SDimitry Andric assert(getKind() == k && "not enough bits for the kind"); 1150b57cec5SDimitry Andric assert(getObjKind() == o && "not enough bits for the object kind"); 1160b57cec5SDimitry Andric assert(getIvarAccessHistory() == IvarAccess && "not enough bits"); 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric public: 1200b57cec5SDimitry Andric Kind getKind() const { return static_cast<Kind>(RawKind); } 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric ObjKind getObjKind() const { 1230b57cec5SDimitry Andric return static_cast<ObjKind>(RawObjectKind); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric unsigned getCount() const { return Cnt; } 1270b57cec5SDimitry Andric unsigned getAutoreleaseCount() const { return ACnt; } 1280b57cec5SDimitry Andric unsigned getCombinedCounts() const { return Cnt + ACnt; } 1290b57cec5SDimitry Andric void clearCounts() { 1300b57cec5SDimitry Andric Cnt = 0; 1310b57cec5SDimitry Andric ACnt = 0; 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric void setCount(unsigned i) { 1340b57cec5SDimitry Andric Cnt = i; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric void setAutoreleaseCount(unsigned i) { 1370b57cec5SDimitry Andric ACnt = i; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric QualType getType() const { return T; } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric /// Returns what the analyzer knows about direct accesses to a particular 1430b57cec5SDimitry Andric /// instance variable. 1440b57cec5SDimitry Andric /// 1450b57cec5SDimitry Andric /// If the object with this refcount wasn't originally from an Objective-C 1460b57cec5SDimitry Andric /// ivar region, this should always return IvarAccessHistory::None. 1470b57cec5SDimitry Andric IvarAccessHistory getIvarAccessHistory() const { 1480b57cec5SDimitry Andric return static_cast<IvarAccessHistory>(RawIvarAccessHistory); 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric bool isOwned() const { 1520b57cec5SDimitry Andric return getKind() == Owned; 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric bool isNotOwned() const { 1560b57cec5SDimitry Andric return getKind() == NotOwned; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric bool isReturnedOwned() const { 1600b57cec5SDimitry Andric return getKind() == ReturnedOwned; 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric bool isReturnedNotOwned() const { 1640b57cec5SDimitry Andric return getKind() == ReturnedNotOwned; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric /// Create a state for an object whose lifetime is the responsibility of the 1680b57cec5SDimitry Andric /// current function, at least partially. 1690b57cec5SDimitry Andric /// 1700b57cec5SDimitry Andric /// Most commonly, this is an owned object with a retain count of +1. 1710b57cec5SDimitry Andric static RefVal makeOwned(ObjKind o, QualType t) { 1720b57cec5SDimitry Andric return RefVal(Owned, o, /*Count=*/1, 0, t, IvarAccessHistory::None); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric /// Create a state for an object whose lifetime is not the responsibility of 1760b57cec5SDimitry Andric /// the current function. 1770b57cec5SDimitry Andric /// 1780b57cec5SDimitry Andric /// Most commonly, this is an unowned object with a retain count of +0. 1790b57cec5SDimitry Andric static RefVal makeNotOwned(ObjKind o, QualType t) { 1800b57cec5SDimitry Andric return RefVal(NotOwned, o, /*Count=*/0, 0, t, IvarAccessHistory::None); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric RefVal operator-(size_t i) const { 1840b57cec5SDimitry Andric return RefVal(getKind(), getObjKind(), getCount() - i, 1850b57cec5SDimitry Andric getAutoreleaseCount(), getType(), getIvarAccessHistory()); 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric RefVal operator+(size_t i) const { 1890b57cec5SDimitry Andric return RefVal(getKind(), getObjKind(), getCount() + i, 1900b57cec5SDimitry Andric getAutoreleaseCount(), getType(), getIvarAccessHistory()); 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric RefVal operator^(Kind k) const { 1940b57cec5SDimitry Andric return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(), 1950b57cec5SDimitry Andric getType(), getIvarAccessHistory()); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric RefVal autorelease() const { 1990b57cec5SDimitry Andric return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1, 2000b57cec5SDimitry Andric getType(), getIvarAccessHistory()); 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric RefVal withIvarAccess() const { 2040b57cec5SDimitry Andric assert(getIvarAccessHistory() == IvarAccessHistory::None); 2050b57cec5SDimitry Andric return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(), 2060b57cec5SDimitry Andric getType(), IvarAccessHistory::AccessedDirectly); 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric RefVal releaseViaIvar() const { 2100b57cec5SDimitry Andric assert(getIvarAccessHistory() == IvarAccessHistory::AccessedDirectly); 2110b57cec5SDimitry Andric return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(), 2120b57cec5SDimitry Andric getType(), IvarAccessHistory::ReleasedAfterDirectAccess); 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric // Comparison, profiling, and pretty-printing. 2160b57cec5SDimitry Andric bool hasSameState(const RefVal &X) const { 2170b57cec5SDimitry Andric return getKind() == X.getKind() && Cnt == X.Cnt && ACnt == X.ACnt && 2180b57cec5SDimitry Andric getIvarAccessHistory() == X.getIvarAccessHistory(); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric bool operator==(const RefVal& X) const { 2220b57cec5SDimitry Andric return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind(); 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric void Profile(llvm::FoldingSetNodeID& ID) const { 2260b57cec5SDimitry Andric ID.Add(T); 2270b57cec5SDimitry Andric ID.AddInteger(RawKind); 2280b57cec5SDimitry Andric ID.AddInteger(Cnt); 2290b57cec5SDimitry Andric ID.AddInteger(ACnt); 2300b57cec5SDimitry Andric ID.AddInteger(RawObjectKind); 2310b57cec5SDimitry Andric ID.AddInteger(RawIvarAccessHistory); 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric void print(raw_ostream &Out) const; 2350b57cec5SDimitry Andric }; 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric class RetainCountChecker 2380b57cec5SDimitry Andric : public Checker< check::Bind, 2390b57cec5SDimitry Andric check::DeadSymbols, 2400b57cec5SDimitry Andric check::BeginFunction, 2410b57cec5SDimitry Andric check::EndFunction, 2420b57cec5SDimitry Andric check::PostStmt<BlockExpr>, 2430b57cec5SDimitry Andric check::PostStmt<CastExpr>, 2440b57cec5SDimitry Andric check::PostStmt<ObjCArrayLiteral>, 2450b57cec5SDimitry Andric check::PostStmt<ObjCDictionaryLiteral>, 2460b57cec5SDimitry Andric check::PostStmt<ObjCBoxedExpr>, 2470b57cec5SDimitry Andric check::PostStmt<ObjCIvarRefExpr>, 2480b57cec5SDimitry Andric check::PostCall, 2490b57cec5SDimitry Andric check::RegionChanges, 2500b57cec5SDimitry Andric eval::Assume, 2510b57cec5SDimitry Andric eval::Call > { 2520b57cec5SDimitry Andric 253*5ffd83dbSDimitry Andric public: 254*5ffd83dbSDimitry Andric std::unique_ptr<RefCountBug> UseAfterRelease; 255*5ffd83dbSDimitry Andric std::unique_ptr<RefCountBug> ReleaseNotOwned; 256*5ffd83dbSDimitry Andric std::unique_ptr<RefCountBug> DeallocNotOwned; 257*5ffd83dbSDimitry Andric std::unique_ptr<RefCountBug> FreeNotOwned; 258*5ffd83dbSDimitry Andric std::unique_ptr<RefCountBug> OverAutorelease; 259*5ffd83dbSDimitry Andric std::unique_ptr<RefCountBug> ReturnNotOwnedForOwned; 260*5ffd83dbSDimitry Andric std::unique_ptr<RefCountBug> LeakWithinFunction; 261*5ffd83dbSDimitry Andric std::unique_ptr<RefCountBug> LeakAtReturn; 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric mutable std::unique_ptr<RetainSummaryManager> Summaries; 264*5ffd83dbSDimitry Andric 265*5ffd83dbSDimitry Andric static std::unique_ptr<CheckerProgramPointTag> DeallocSentTag; 266*5ffd83dbSDimitry Andric static std::unique_ptr<CheckerProgramPointTag> CastFailTag; 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric /// Track Objective-C and CoreFoundation objects. 2690b57cec5SDimitry Andric bool TrackObjCAndCFObjects = false; 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric /// Track sublcasses of OSObject. 2720b57cec5SDimitry Andric bool TrackOSObjects = false; 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric /// Track initial parameters (for the entry point) for NS/CF objects. 2750b57cec5SDimitry Andric bool TrackNSCFStartParam = false; 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric RetainCountChecker() {}; 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const { 2800b57cec5SDimitry Andric if (!Summaries) 2810b57cec5SDimitry Andric Summaries.reset( 2820b57cec5SDimitry Andric new RetainSummaryManager(Ctx, TrackObjCAndCFObjects, TrackOSObjects)); 2830b57cec5SDimitry Andric return *Summaries; 2840b57cec5SDimitry Andric } 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric RetainSummaryManager &getSummaryManager(CheckerContext &C) const { 2870b57cec5SDimitry Andric return getSummaryManager(C.getASTContext()); 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric void printState(raw_ostream &Out, ProgramStateRef State, 2910b57cec5SDimitry Andric const char *NL, const char *Sep) const override; 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; 2940b57cec5SDimitry Andric void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; 2950b57cec5SDimitry Andric void checkPostStmt(const CastExpr *CE, CheckerContext &C) const; 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const; 2980b57cec5SDimitry Andric void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const; 2990b57cec5SDimitry Andric void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const; 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const; 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric void checkSummary(const RetainSummary &Summ, const CallEvent &Call, 3060b57cec5SDimitry Andric CheckerContext &C) const; 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric void processSummaryOfInlined(const RetainSummary &Summ, 3090b57cec5SDimitry Andric const CallEvent &Call, 3100b57cec5SDimitry Andric CheckerContext &C) const; 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const; 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, 3150b57cec5SDimitry Andric bool Assumption) const; 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric ProgramStateRef 3180b57cec5SDimitry Andric checkRegionChanges(ProgramStateRef state, 3190b57cec5SDimitry Andric const InvalidatedSymbols *invalidated, 3200b57cec5SDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 3210b57cec5SDimitry Andric ArrayRef<const MemRegion *> Regions, 3220b57cec5SDimitry Andric const LocationContext* LCtx, 3230b57cec5SDimitry Andric const CallEvent *Call) const; 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric ExplodedNode* checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, 3260b57cec5SDimitry Andric ExplodedNode *Pred, RetEffect RE, RefVal X, 3270b57cec5SDimitry Andric SymbolRef Sym, ProgramStateRef state) const; 3280b57cec5SDimitry Andric 3290b57cec5SDimitry Andric void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; 3300b57cec5SDimitry Andric void checkBeginFunction(CheckerContext &C) const; 3310b57cec5SDimitry Andric void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const; 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym, 3340b57cec5SDimitry Andric RefVal V, ArgEffect E, RefVal::Kind &hasErr, 3350b57cec5SDimitry Andric CheckerContext &C) const; 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric const RefCountBug &errorKindToBugKind(RefVal::Kind ErrorKind, 3380b57cec5SDimitry Andric SymbolRef Sym) const; 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange, 3410b57cec5SDimitry Andric RefVal::Kind ErrorKind, SymbolRef Sym, 3420b57cec5SDimitry Andric CheckerContext &C) const; 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric void processObjCLiterals(CheckerContext &C, const Expr *Ex) const; 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric ProgramStateRef handleSymbolDeath(ProgramStateRef state, 3470b57cec5SDimitry Andric SymbolRef sid, RefVal V, 3480b57cec5SDimitry Andric SmallVectorImpl<SymbolRef> &Leaked) const; 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric ProgramStateRef 3510b57cec5SDimitry Andric handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred, 3520b57cec5SDimitry Andric const ProgramPointTag *Tag, CheckerContext &Ctx, 3530b57cec5SDimitry Andric SymbolRef Sym, 3540b57cec5SDimitry Andric RefVal V, 3550b57cec5SDimitry Andric const ReturnStmt *S=nullptr) const; 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric ExplodedNode *processLeaks(ProgramStateRef state, 3580b57cec5SDimitry Andric SmallVectorImpl<SymbolRef> &Leaked, 3590b57cec5SDimitry Andric CheckerContext &Ctx, 3600b57cec5SDimitry Andric ExplodedNode *Pred = nullptr) const; 3610b57cec5SDimitry Andric 362*5ffd83dbSDimitry Andric static const CheckerProgramPointTag &getDeallocSentTag() { 363*5ffd83dbSDimitry Andric return *DeallocSentTag; 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric 366*5ffd83dbSDimitry Andric static const CheckerProgramPointTag &getCastFailTag() { return *CastFailTag; } 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric private: 3690b57cec5SDimitry Andric /// Perform the necessary checks and state adjustments at the end of the 3700b57cec5SDimitry Andric /// function. 3710b57cec5SDimitry Andric /// \p S Return statement, may be null. 3720b57cec5SDimitry Andric ExplodedNode * processReturn(const ReturnStmt *S, CheckerContext &C) const; 3730b57cec5SDimitry Andric }; 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3760b57cec5SDimitry Andric // RefBindings - State used to track object reference counts. 3770b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym); 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric /// Returns true if this stack frame is for an Objective-C method that is a 3820b57cec5SDimitry Andric /// property getter or setter whose body has been synthesized by the analyzer. 3830b57cec5SDimitry Andric inline bool isSynthesizedAccessor(const StackFrameContext *SFC) { 3840b57cec5SDimitry Andric auto Method = dyn_cast_or_null<ObjCMethodDecl>(SFC->getDecl()); 3850b57cec5SDimitry Andric if (!Method || !Method->isPropertyAccessor()) 3860b57cec5SDimitry Andric return false; 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric return SFC->getAnalysisDeclContext()->isBodyAutosynthesized(); 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric } // end namespace retaincountchecker 3920b57cec5SDimitry Andric } // end namespace ento 3930b57cec5SDimitry Andric } // end namespace clang 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric #endif 396