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.