clang: lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
36#include "llvm/ADT/Twine.h"
37
38using namespace clang;
39using namespace ento;
40using namespace ast_matchers;
41
42namespace {
43
44const char *ProblematicWriteBind = "problematicwrite";
45const char *CapturedBind = "capturedbind";
46const char *ParamBind = "parambind";
47const char *IsMethodBind = "ismethodbind";
48const char *IsARPBind = "isautoreleasepoolbind";
49
50class ObjCAutoreleaseWriteChecker : public Checkercheck::ASTCodeBody {
51public:
52 void checkASTCodeBody(const Decl *D,
55private:
56 std::vectorstd::string SelectorsWithAutoreleasingPool = {
57
58 "enumerateObjectsUsingBlock:",
59 "enumerateObjectsWithOptions:usingBlock:",
60
61
62 "enumerateObjectsAtIndexes:options:usingBlock:",
63 "indexOfObjectAtIndexes:options:passingTest:",
64 "indexesOfObjectsAtIndexes:options:passingTest:",
65 "indexOfObjectPassingTest:",
66 "indexOfObjectWithOptions:passingTest:",
67 "indexesOfObjectsPassingTest:",
68 "indexesOfObjectsWithOptions:passingTest:",
69
70
71 "enumerateKeysAndObjectsUsingBlock:",
72 "enumerateKeysAndObjectsWithOptions:usingBlock:",
73 "keysOfEntriesPassingTest:",
74 "keysOfEntriesWithOptions:passingTest:",
75
76
77 "objectsPassingTest:",
78 "objectsWithOptions:passingTest:",
79 "enumerateIndexPathsWithOptions:usingBlock:",
80
81
82 "enumerateIndexesWithOptions:usingBlock:",
83 "enumerateIndexesUsingBlock:",
84 "enumerateIndexesInRange:options:usingBlock:",
85 "enumerateRangesUsingBlock:",
86 "enumerateRangesWithOptions:usingBlock:",
87 "enumerateRangesInRange:options:usingBlock:",
88 "indexPassingTest:",
89 "indexesPassingTest:",
90 "indexWithOptions:passingTest:",
91 "indexesWithOptions:passingTest:",
92 "indexInRange:options:passingTest:",
93 "indexesInRange:options:passingTest:"
94 };
95
96 std::vectorstd::string FunctionsWithAutoreleasingPool = {
97 "dispatch_async", "dispatch_group_async", "dispatch_barrier_async"};
98};
99}
100
101static inline std::vectorllvm::StringRef
102toRefs(const std::vectorstd::string &V) {
103 return std::vectorllvm::StringRef(V.begin(), V.end());
104}
105
106static decltype(auto)
107callsNames(const std::vectorstd::string &FunctionNames) {
109}
110
113 const ObjCAutoreleaseWriteChecker *Checker) {
115
117 QualType Ty = PVD->getType();
119 return;
120 const char *ActionMsg = "Write to";
121 const auto *MarkedStmt = Match.getNodeAs<Expr>(ProblematicWriteBind);
122 bool IsCapture = false;
123
124
125 if (!MarkedStmt) {
126 MarkedStmt = Match.getNodeAs<Expr>(CapturedBind);
127 assert(MarkedStmt);
128 ActionMsg = "Capture of";
129 IsCapture = true;
130 }
131
135
137 const char *FunctionDescription = IsMethod ? "method" : "function";
139
141 llvm::raw_svector_ostream BugName(BugNameBuf);
142 BugName << ActionMsg
143 << " autoreleasing out parameter inside autorelease pool";
144
146 llvm::raw_svector_ostream BugMessage(BugMessageBuf);
147 BugMessage << ActionMsg << " autoreleasing out parameter ";
148 if (IsCapture)
149 BugMessage << "'" + PVD->getName() + "' ";
150
151 BugMessage << "inside ";
152 if (IsARP)
153 BugMessage << "locally-scoped autorelease pool;";
154 else
155 BugMessage << "autorelease pool that may exit before "
156 << FunctionDescription << " returns;";
157
158 BugMessage << " consider writing first to a strong local variable"
159 " declared outside ";
160 if (IsARP)
161 BugMessage << "of the autorelease pool";
162 else
163 BugMessage << "of the block";
164
168}
169
170void ObjCAutoreleaseWriteChecker::checkASTCodeBody(const Decl *D,
173
174 auto DoublePointerParamM =
177 .bind(ParamBind);
178
179 auto ReferencedParamM =
181
182
185 hasOperatorName("*"),
186 hasUnaryOperand(
187 ignoringParenImpCasts(ReferencedParamM))
188 )),
189 hasOperatorName("=")
190 ).bind(ProblematicWriteBind);
191
192 auto ArgumentCaptureM = hasAnyArgument(
193 ignoringParenImpCasts(ReferencedParamM));
194 auto CapturedInParamM = stmt(anyOf(
197
198
199 auto WritesOrCapturesInBlockM = hasAnyArgument(allOf(
202 stmt(anyOf(WritesIntoM, CapturedInParamM))
203 )));
204
205 auto BlockPassedToMarkedFuncM = stmt(anyOf(
207 callsNames(FunctionsWithAutoreleasingPool), WritesOrCapturesInBlockM)),
210 WritesOrCapturesInBlockM))
211 ));
212
213
214 auto WritesOrCapturesInPoolM =
217 .bind(IsARPBind);
218
219 auto HasParamAndWritesInMarkedFuncM =
220 allOf(hasAnyParameter(DoublePointerParamM),
223
225 objcMethodDecl(HasParamAndWritesInMarkedFuncM).bind(IsMethodBind),
226 functionDecl(HasParamAndWritesInMarkedFuncM),
227 blockDecl(HasParamAndWritesInMarkedFuncM)));
228
232}
233
234void ento::registerAutoreleaseWriteChecker(CheckerManager &Mgr) {
236}
237
238bool ento::shouldRegisterAutoreleaseWriteChecker(const CheckerManager &mgr) {
239 return true;
240}
static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)
static decltype(auto) callsNames(const std::vector< std::string > &FunctionNames)
static std::vector< llvm::StringRef > toRefs(const std::vector< std::string > &V)
AnalysisDeclContext contains the context data for the function, method or block under analysis.
const Decl * getDecl() const
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Represents Objective-C's @autoreleasepool Statement.
ObjCMethodDecl - Represents an instance or class method declaration.
Represents a parameter to a function.
A (possibly-)qualified type.
@ OCL_Autoreleasing
Assigning into this object requires a lifetime extension.
A trivial tuple used to represent a source range.
Maps string IDs to AST nodes matched by parts of a matcher.
const T * getNodeAs(StringRef ID) const
Returns the AST node bound to ID.
ASTContext & getASTContext() override
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges={}, ArrayRef< FixItHint > Fixits={})
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
A Range represents the closed range [from, to].
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclRefExpr > declRefExpr
Matches expressions that refer to declarations.
const AstTypeMatcher< ObjCObjectPointerType > objcObjectPointerType
Matches an Objective-C object pointer type, which is different from a pointer type,...
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
const internal::VariadicDynCastAllOfMatcher< Decl, ObjCMethodDecl > objcMethodDecl
Matches Objective-C method declarations.
const internal::VariadicDynCastAllOfMatcher< Decl, ParmVarDecl > parmVarDecl
Matches parameter variable declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, ObjCAutoreleasePoolStmt > autoreleasePoolStmt
Matches an Objective-C autorelease pool statement.
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachDescendantMatcher > forEachDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
const internal::VariadicFunction< internal::Matcher< ObjCMessageExpr >, StringRef, internal::hasAnySelectorFunc > hasAnySelector
Matches when at least one of the supplied string equals to the Selector.getAsString()
const internal::VariadicDynCastAllOfMatcher< Stmt, UnaryOperator > unaryOperator
Matches unary operator expressions.
const internal::VariadicFunction< internal::Matcher< NamedDecl >, StringRef, internal::hasAnyNameFunc > hasAnyName
Matches NamedDecl nodes that have any of the specified names.
const internal::VariadicDynCastAllOfMatcher< Stmt, ObjCMessageExpr > objcMessageExpr
Matches ObjectiveC Message invocation expressions.
const AstTypeMatcher< BlockPointerType > blockPointerType
Matches block pointer types, i.e.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
const internal::VariadicAllOfMatcher< Decl > decl
Matches declarations.
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.
const internal::VariadicDynCastAllOfMatcher< Decl, BlockDecl > blockDecl
Matches block declarations.
const char *const MemoryRefCount
The JSON file list parser is used to communicate input to InstallAPI.