Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: e4583151cc638c94cd203d3e057c8a2994ab1d8f [file] [log] [blame]
Avi Drissmandfd880852022-09-15 20:11:091// Copyright 2016 The Chromium Authors
dskiba2bc89462016-04-06 15:51:062// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "CheckIPCVisitor.h"
6
7using namespace clang;
8
9namespace chrome_checker {
10
11namespace {
12
13const char kWriteParamBadType[] =
Peter Boströmbcda49b2022-11-22 20:02:2914 "[chromium-ipc] IPC::WriteParam() is called on blocklisted type '%0'%1.";
dskiba2bc89462016-04-06 15:51:0615
16const char kTupleBadType[] =
17 "[chromium-ipc] IPC tuple references banned type '%0'%1.";
18
19const char kWriteParamBadSignature[] =
20 "[chromium-ipc] IPC::WriteParam() is expected to have two arguments.";
21
22const char kNoteSeeHere[] =
23 "see here";
24
25} // namespace
26
27CheckIPCVisitor::CheckIPCVisitor(CompilerInstance& compiler)
28 : compiler_(compiler), context_(nullptr) {
29 auto& diagnostics = compiler_.getDiagnostics();
30 error_write_param_bad_type_ = diagnostics.getCustomDiagID(
31 DiagnosticsEngine::Error, kWriteParamBadType);
32 error_tuple_bad_type_ = diagnostics.getCustomDiagID(
33 DiagnosticsEngine::Error, kTupleBadType);
34 error_write_param_bad_signature_ = diagnostics.getCustomDiagID(
35 DiagnosticsEngine::Error, kWriteParamBadSignature);
36 note_see_here_ = diagnostics.getCustomDiagID(
37 DiagnosticsEngine::Note, kNoteSeeHere);
38
Peter Boströmbcda49b2022-11-22 20:02:2939 blocklisted_typedefs_ = llvm::StringSet<>({
dskiba2bc89462016-04-06 15:51:0640 "intmax_t",
41 "uintmax_t",
42 "intptr_t",
43 "uintptr_t",
44 "wint_t",
45 "size_t",
46 "rsize_t",
47 "ssize_t",
48 "ptrdiff_t",
49 "dev_t",
50 "off_t",
51 "clock_t",
52 "time_t",
53 "suseconds_t"
54 });
55}
56
57void CheckIPCVisitor::BeginDecl(Decl* decl) {
58 decl_stack_.push_back(decl);
59}
60
61void CheckIPCVisitor::EndDecl() {
62 decl_stack_.pop_back();
63}
64
65void CheckIPCVisitor::VisitTemplateSpecializationType(
66 TemplateSpecializationType* spec) {
67 ValidateCheckedTuple(spec);
68}
69
70void CheckIPCVisitor::VisitCallExpr(CallExpr* call_expr) {
71 ValidateWriteParam(call_expr);
72}
73
74bool CheckIPCVisitor::ValidateWriteParam(const CallExpr* call_expr) {
75 const FunctionDecl* callee_decl = call_expr->getDirectCallee();
76 if (!callee_decl ||
77 callee_decl->getQualifiedNameAsString() != "IPC::WriteParam") {
78 return true;
79 }
80
81 return ValidateWriteParamSignature(call_expr) &&
82 ValidateWriteParamArgument(call_expr->getArg(1));
83}
84
85// Checks that IPC::WriteParam() has expected signature.
86bool CheckIPCVisitor::ValidateWriteParamSignature(
87 const CallExpr* call_expr) {
88 if (call_expr->getNumArgs() != 2) {
89 compiler_.getDiagnostics().Report(
90 call_expr->getExprLoc(), error_write_param_bad_signature_);
91 return false;
92 }
93 return true;
94}
95
96// Checks that IPC::WriteParam() argument type is allowed.
97// See CheckType() for specifics.
98bool CheckIPCVisitor::ValidateWriteParamArgument(const Expr* arg_expr) {
99 if (auto* parent_fn_decl = GetParentDecl<FunctionDecl>()) {
100 auto template_kind = parent_fn_decl->getTemplatedKind();
101 if (template_kind != FunctionDecl::TK_NonTemplate &&
102 template_kind != FunctionDecl::TK_FunctionTemplate) {
103 // Skip all specializations - we don't check WriteParam() on dependent
104 // types (typedef info gets lost), and we checked all non-dependent uses
105 // earlier (when we checked the template itself).
106 return true;
107 }
108 }
109
110 QualType arg_type;
111
112 arg_expr = arg_expr->IgnoreImplicit();
113 if (auto* cast_expr = dyn_cast<ExplicitCastExpr>(arg_expr)) {
114 arg_type = cast_expr->getTypeAsWritten();
115 } else {
116 arg_type = arg_expr->getType();
117 }
118
119 CheckDetails details;
120 if (CheckType(arg_type, &details)) {
121 return true;
122 }
123
124 ReportCheckError(details,
125 arg_expr->getExprLoc(),
126 error_write_param_bad_type_);
127
128 return false;
129}
130
131// Checks that IPC::CheckedTuple<> is specialized with allowed types.
132// See CheckType() above for specifics.
133bool CheckIPCVisitor::ValidateCheckedTuple(
134 const TemplateSpecializationType* spec) {
135 TemplateDecl* decl = spec->getTemplateName().getAsTemplateDecl();
136 if (!decl || decl->getQualifiedNameAsString() != "IPC::CheckedTuple") {
137 return true;
138 }
139
140 bool valid = true;
Nico Weber69c52682022-10-25 16:03:09141 for (const TemplateArgument& arg : spec->template_arguments()) {
dskiba2bc89462016-04-06 15:51:06142 CheckDetails details;
143 if (CheckTemplateArgument(arg, &details)) {
144 continue;
145 }
146
147 valid = false;
148
149 auto* parent_decl = GetParentDecl<Decl>();
150 ReportCheckError(
Reid Klecknerb4bebe1a2018-09-06 21:33:56151 details, parent_decl ? parent_decl->getBeginLoc() : SourceLocation(),
dskiba2bc89462016-04-06 15:51:06152 error_tuple_bad_type_);
153 }
154
155 return valid;
156}
157
158template <typename T>
159const T* CheckIPCVisitor::GetParentDecl() const {
160 for (auto i = decl_stack_.rbegin(); i != decl_stack_.rend(); ++i) {
161 if (auto* parent = dyn_cast_or_null<T>(*i)) {
162 return parent;
163 }
164 }
165 return nullptr;
166}
167
168
169bool CheckIPCVisitor::IsBlacklistedType(QualType type) const {
170 return context_->hasSameUnqualifiedType(type, context_->LongTy) ||
171 context_->hasSameUnqualifiedType(type, context_->UnsignedLongTy);
172}
173
174bool CheckIPCVisitor::IsBlacklistedTypedef(const TypedefNameDecl* tdef) const {
Peter Boströmbcda49b2022-11-22 20:02:29175 return blocklisted_typedefs_.find(tdef->getName()) !=
176 blocklisted_typedefs_.end();
dskiba2bc89462016-04-06 15:51:06177}
178
Peter Boströmbcda49b2022-11-22 20:02:29179// Checks that integer type is allowed (not blocklisted).
dskiba2bc89462016-04-06 15:51:06180bool CheckIPCVisitor::CheckIntegerType(QualType type,
181 CheckDetails* details) const {
182 bool seen_typedef = false;
183 while (true) {
184 details->exit_type = type;
185
186 if (auto* tdef = dyn_cast<TypedefType>(type)) {
187 if (IsBlacklistedTypedef(tdef->getDecl())) {
188 return false;
189 }
190 details->typedefs.push_back(tdef);
191 seen_typedef = true;
192 }
193
194 QualType desugared_type =
195 type->getLocallyUnqualifiedSingleStepDesugaredType();
196 if (desugared_type == type) {
197 break;
198 }
199
200 type = desugared_type;
201 }
202
203 return seen_typedef || !IsBlacklistedType(type);
204}
205
Peter Boströmbcda49b2022-11-22 20:02:29206// Checks that |type| is allowed (not blocklisted), recursively visiting
dskiba2bc89462016-04-06 15:51:06207// template specializations.
208bool CheckIPCVisitor::CheckType(QualType type, CheckDetails* details) const {
209 if (type->isReferenceType()) {
210 type = type->getPointeeType();
211 }
212 type = type.getLocalUnqualifiedType();
213
214 if (details->entry_type.isNull()) {
215 details->entry_type = type;
216 }
217
218 if (type->isIntegerType()) {
219 return CheckIntegerType(type, details);
220 }
221
222 while (true) {
223 if (auto* spec = dyn_cast<TemplateSpecializationType>(type)) {
Nico Weber69c52682022-10-25 16:03:09224 for (const TemplateArgument& arg : spec->template_arguments()) {
dskiba2bc89462016-04-06 15:51:06225 if (!CheckTemplateArgument(arg, details)) {
226 return false;
227 }
228 }
229 return true;
230 }
231
232 if (auto* record = dyn_cast<RecordType>(type)) {
233 if (auto* spec = dyn_cast<ClassTemplateSpecializationDecl>(
Arthur Eubanks3ef1b382025-08-13 03:28:24234 record->getOriginalDecl())) {
dskiba2bc89462016-04-06 15:51:06235 const TemplateArgumentList& args = spec->getTemplateArgs();
236 for (unsigned i = 0; i != args.size(); ++i) {
237 if (!CheckTemplateArgument(args[i], details)) {
238 return false;
239 }
240 }
241 }
242 return true;
243 }
244
245 if (auto* tdef = dyn_cast<TypedefType>(type)) {
246 details->typedefs.push_back(tdef);
247 }
248
249 QualType desugared_type =
250 type->getLocallyUnqualifiedSingleStepDesugaredType();
251 if (desugared_type == type) {
252 break;
253 }
254
255 type = desugared_type;
256 }
257
258 return true;
259}
260
261bool CheckIPCVisitor::CheckTemplateArgument(const TemplateArgument& arg,
262 CheckDetails* details) const {
263 return arg.getKind() != TemplateArgument::Type ||
264 CheckType(arg.getAsType(), details);
265}
266
267void CheckIPCVisitor::ReportCheckError(const CheckDetails& details,
268 SourceLocation loc,
269 unsigned error) {
270 DiagnosticsEngine& diagnostics = compiler_.getDiagnostics();
271
272 std::string entry_type = details.entry_type.getAsString();
273 std::string exit_type = details.exit_type.getAsString();
274
275 std::string via;
276 if (entry_type != exit_type) {
277 via = " via '" + entry_type + "'";
278 }
279 diagnostics.Report(loc, error) << exit_type << via;
280
281 for (const TypedefType* tdef: details.typedefs) {
282 diagnostics.Report(tdef->getDecl()->getLocation(), note_see_here_);
283 }
284}
285
286} // namespace chrome_checker