Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: tools/clang/plugins/CheckIPCAction.cpp

Issue 1665363002: Clang plugin to check that unstable types are not used in IPC. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/clang/plugins/CMakeLists.txt ('k') | tools/clang/plugins/tests/ipc.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "clang/Frontend/FrontendPluginRegistry.h"
6 #include "clang/AST/AST.h"
7 #include "clang/AST/ASTConsumer.h"
8 #include "clang/AST/RecursiveASTVisitor.h"
9 #include "clang/Frontend/CompilerInstance.h"
10 #include "llvm/Support/raw_ostream.h"
11
12 #include <stack>
13
14 using namespace clang;
15
16 namespace {
17
18 const char kWriteParamSizeT[] =
19 "[chromium-ipc] IPC::WriteParam() is called on size_t.";
20
21 const char kWriteParamTemplate[] =
22 "[chromium-ipc] IPC::WriteParam() is called in a template instantiation "
23 "on a type equivalent to size_t.";
24
25 const char kNoteInstantiation[] =
26 "instantiation: %0";
27
28 const char kTupleSizeT[] =
29 "[chromium-ipc] IPC::ParamTuple specialized with size_t.";
30
31
32 bool IsSizeT(ASTContext& context, QualType type) {
33 type = type.getLocalUnqualifiedType();
34 if (!context.hasSameUnqualifiedType(type, context.getSizeType())) {
35 return false;
36 }
37 while (true) {
38 if (type.getAsString() == "size_t") {
39 return true;
40 }
41 QualType desugaredType = type.getSingleStepDesugaredType(context);
dcheng 2016/02/05 19:42:27 Nit: desugared_type
42 if (desugaredType == type) {
43 return false;
44 }
45 type = desugaredType.getLocalUnqualifiedType();
46 }
47 }
48
49 class SizeTExprFinder: RecursiveASTVisitor<SizeTExprFinder> {
50 public:
51 static Expr* Find(ASTContext& context, Expr* expr) {
52 SizeTExprFinder finder(context);
53 finder.TraverseStmt(expr);
54 return finder.found_;
55 }
56
57 private:
58 typedef RecursiveASTVisitor<SizeTExprFinder> Base;
59 friend Base;
60
61 SizeTExprFinder(ASTContext& context): context_(context), found_(nullptr) {}
dcheng 2016/02/05 19:42:27 explicit
62
63 bool shouldVisitTemplateInstantiations() const { return true; }
64
65 bool TraverseStmt(Stmt* stmt) {
66 if (found_) {
67 return false;
68 }
69 Expr* expr = dyn_cast_or_null<Expr>(stmt);
70 if (!expr) {
71 return false;
72 }
73 QualType type = expr->getType();
74 if (!context_.hasSameUnqualifiedType(type, context_.getSizeType())) {
75 return false;
76 }
77 if (IsSizeT(context_, type)) {
78 found_ = expr;
79 return false;
80 }
81 return Base::TraverseStmt(expr);
82 }
83
84 ASTContext& context_;
85 Expr* found_;
86 };
87
88 class Visitor: public RecursiveASTVisitor<Visitor> {
89 typedef RecursiveASTVisitor<Visitor> Base;
90 public:
91 Visitor(CompilerInstance& compiler, ASTContext& context)
92 : compiler_(compiler), context_(context) {
93 auto& diagnostics = compiler_.getDiagnostics();
94 error_write_param_size_t_ = diagnostics.getCustomDiagID(
95 DiagnosticsEngine::Error, kWriteParamSizeT);
96 error_write_param_template_ = diagnostics.getCustomDiagID(
97 DiagnosticsEngine::Error, kWriteParamTemplate);
98 note_instantiation_ = diagnostics.getCustomDiagID(
99 DiagnosticsEngine::Note, kNoteInstantiation);
100 error_tuple_size_t_ = diagnostics.getCustomDiagID(
101 DiagnosticsEngine::Error, kTupleSizeT);
102 }
103
104 bool shouldVisitTemplateInstantiations() const { return true; }
105
106 bool VisitTemplateSpecializationType(TemplateSpecializationType* spec) {
107 TemplateDecl* decl = spec->getTemplateName().getAsTemplateDecl();
108 if (decl && decl->getQualifiedNameAsString() == "IPC::ParamTuple") {
109 for (unsigned i = 0; i != spec->getNumArgs(); ++i) {
110 QualType arg_type = spec->getArg(i).getAsType();
111 if (IsSizeT(context_, arg_type)) {
112 compiler_.getDiagnostics().Report(
113 getParentDecl()->getLocStart(), error_tuple_size_t_);
114 break;
115 }
116 }
117 }
118 return true;
119 }
120
121 bool VisitCallExpr(CallExpr* call) {
122 const FunctionDecl* callee = call->getDirectCallee();
123 if (!callee || callee->getQualifiedNameAsString() != "IPC::WriteParam") {
124 return true;
125 }
126
127 // TODO: what about WriteParam<size_t>((__SIZE_TYPE__)0)?
128 // It will be caught by missing unsigned long ParamTraits
129 // specialization, but we can also catch it here.
130
131 // Don't bother if we're not called with __SIZE_TYPE__
132 bool called_with_size_type = false;
133 for (const Expr* argument: call->arguments()) {
134 if (context_.hasSameUnqualifiedType(
135 argument->getType(), context_.getSizeType())) {
136 called_with_size_type = true;
137 break;
138 }
139 }
140 if (!called_with_size_type) {
141 return true;
142 }
143
144 // TODO: what about lambdas? Do we need to search more?
145 if (auto parent = dyn_cast_or_null<FunctionDecl>(getParentDecl())) {
146 if (CheckWriteParamInstantiation(call, parent)) {
147 return true;
148 }
149 }
150
151 for (Expr* argument: call->arguments()) {
152 Expr* sizet_expr = SizeTExprFinder::Find(context_, argument);
153 if (sizet_expr) {
154 compiler_.getDiagnostics().Report(
155 sizet_expr->getExprLoc(), error_write_param_size_t_);
156 }
157 }
158
159 return true;
160 }
161
162 bool TraverseDecl(Decl* decl) {
163 parent_decls_.push(decl);
164 bool result = Base::TraverseDecl(decl);
165 parent_decls_.pop();
166 return result;
167 }
168
169 private:
170 Decl* getParentDecl() const {
dcheng 2016/02/05 19:42:27 GetParentDecl()?
171 return parent_decls_.empty() ? nullptr : parent_decls_.top();
172 }
173
174 bool CheckWriteParamInstantiation(CallExpr* call, FunctionDecl* parent) {
175 // Only check implicit instantiations
176 if (parent->getTemplatedKind() == FunctionDecl::TK_NonTemplate ||
177 parent->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
178 return false;
179 }
180
181 // Check that we are inside IPC::ParamTraits<IPC::ParamTuple<..>>
182 bool param_tuple_specialization = false;
183 if (auto cxx_method = dyn_cast<CXXMethodDecl>(parent)) {
184 auto spec = dyn_cast<ClassTemplateSpecializationDecl>(
185 cxx_method->getParent());
186 if (spec && spec->getQualifiedNameAsString() == "IPC::ParamTraits") {
187 const TemplateArgument& arg = spec->getTemplateArgs().get(0);
188 auto arg_type = dyn_cast<TagType>(arg.getAsType().getTypePtr());
189 param_tuple_specialization =
190 arg_type &&
191 arg_type->getDecl()->getQualifiedNameAsString() ==
192 "IPC::ParamTuple";
193 }
194 }
195 if (param_tuple_specialization) {
196 return false;
197 }
198
199 compiler_.getDiagnostics().Report(
200 call->getExprLoc(), error_write_param_template_);
201
202 // TODO: use TemplateSpecializationType::PrintTemplateArgumentList to
203 // include function's template arguments
204 compiler_.getDiagnostics().Report(call->getExprLoc(), note_instantiation_)
205 << parent->getQualifiedNameAsString();
206 return true;
207 }
208
209 CompilerInstance& compiler_;
210 ASTContext& context_;
211
212 unsigned error_write_param_size_t_;
213 unsigned error_write_param_template_;
214 unsigned error_tuple_size_t_;
215 unsigned note_instantiation_;
216
217 std::stack<Decl*> parent_decls_;
218 };
219
220 class Consumer: public ASTConsumer {
221 public:
222 Consumer(CompilerInstance& compiler): compiler_(compiler) {}
223
224 void HandleTranslationUnit(ASTContext& context) override {
225 Visitor(compiler_, context).TraverseDecl(context.getTranslationUnitDecl());
226 }
227
228 private:
229 CompilerInstance& compiler_;
230 };
231
232 class Plugin: public PluginASTAction {
233 protected:
234 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance& compiler,
235 llvm::StringRef) override {
236 return llvm::make_unique<Consumer>(compiler);
237 }
238
239 bool ParseArgs(const CompilerInstance&,
240 const std::vector<std::string>&) override {
241 return true;
242 }
243 };
244
245 } // namespace
246
247 static FrontendPluginRegistry::Add<Plugin> X(
248 "check-ipc",
249 "Checks for size_t in IPC messages");
OLDNEW
« no previous file with comments | « tools/clang/plugins/CMakeLists.txt ('k') | tools/clang/plugins/tests/ipc.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698