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
RefVal(Kind k,ObjKind o,unsigned cnt,unsigned acnt,QualType t,IvarAccessHistory IvarAccess)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:
getKind()1200b57cec5SDimitry Andric Kind getKind() const { return static_cast<Kind>(RawKind); }
1210b57cec5SDimitry Andric
getObjKind()1220b57cec5SDimitry Andric ObjKind getObjKind() const {
1230b57cec5SDimitry Andric return static_cast<ObjKind>(RawObjectKind);
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric
getCount()1260b57cec5SDimitry Andric unsigned getCount() const { return Cnt; }
getAutoreleaseCount()1270b57cec5SDimitry Andric unsigned getAutoreleaseCount() const { return ACnt; }
getCombinedCounts()1280b57cec5SDimitry Andric unsigned getCombinedCounts() const { return Cnt + ACnt; }
clearCounts()1290b57cec5SDimitry Andric void clearCounts() {
1300b57cec5SDimitry Andric Cnt = 0;
1310b57cec5SDimitry Andric ACnt = 0;
1320b57cec5SDimitry Andric }
setCount(unsigned i)1330b57cec5SDimitry Andric void setCount(unsigned i) {
1340b57cec5SDimitry Andric Cnt = i;
1350b57cec5SDimitry Andric }
setAutoreleaseCount(unsigned i)1360b57cec5SDimitry Andric void setAutoreleaseCount(unsigned i) {
1370b57cec5SDimitry Andric ACnt = i;
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric
getType()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.
getIvarAccessHistory()1470b57cec5SDimitry Andric IvarAccessHistory getIvarAccessHistory() const {
1480b57cec5SDimitry Andric return static_cast<IvarAccessHistory>(RawIvarAccessHistory);
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric
isOwned()1510b57cec5SDimitry Andric bool isOwned() const {
1520b57cec5SDimitry Andric return getKind() == Owned;
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric
isNotOwned()1550b57cec5SDimitry Andric bool isNotOwned() const {
1560b57cec5SDimitry Andric return getKind() == NotOwned;
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric
isReturnedOwned()1590b57cec5SDimitry Andric bool isReturnedOwned() const {
1600b57cec5SDimitry Andric return getKind() == ReturnedOwned;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric
isReturnedNotOwned()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.
makeOwned(ObjKind o,QualType t)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.
makeNotOwned(ObjKind o,QualType t)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
autorelease()1980b57cec5SDimitry Andric RefVal autorelease() const {
1990b57cec5SDimitry Andric return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
2000b57cec5SDimitry Andric getType(), getIvarAccessHistory());
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric
withIvarAccess()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
releaseViaIvar()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.
hasSameState(const RefVal & X)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
Profile(llvm::FoldingSetNodeID & ID)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
RetainCountChecker()2770b57cec5SDimitry Andric RetainCountChecker() {};
2780b57cec5SDimitry Andric
getSummaryManager(ASTContext & Ctx)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
getSummaryManager(CheckerContext & C)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
getDeallocSentTag()362*5ffd83dbSDimitry Andric static const CheckerProgramPointTag &getDeallocSentTag() {
363*5ffd83dbSDimitry Andric return *DeallocSentTag;
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric
getCastFailTag()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.
isSynthesizedAccessor(const StackFrameContext * SFC)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