| OLD | NEW |
| (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 "CheckIPCVisitor.h" | |
| 6 | |
| 7 using namespace clang; | |
| 8 | |
| 9 namespace chrome_checker { | |
| 10 | |
| 11 namespace { | |
| 12 | |
| 13 const char kWriteParamBadType[] = | |
| 14 "[chromium-ipc] IPC::WriteParam() is called on blacklisted type '%0'%1."; | |
| 15 | |
| 16 const char kTupleBadType[] = | |
| 17 "[chromium-ipc] IPC tuple references banned type '%0'%1."; | |
| 18 | |
| 19 const char kWriteParamBadSignature[] = | |
| 20 "[chromium-ipc] IPC::WriteParam() is expected to have two arguments."; | |
| 21 | |
| 22 const char kNoteSeeHere[] = | |
| 23 "see here"; | |
| 24 | |
| 25 } // namespace | |
| 26 | |
| 27 CheckIPCVisitor::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 | |
| 39 blacklisted_typedefs_ = llvm::StringSet<>({ | |
| 40 "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 | |
| 57 void CheckIPCVisitor::BeginDecl(Decl* decl) { | |
| 58 decl_stack_.push_back(decl); | |
| 59 } | |
| 60 | |
| 61 void CheckIPCVisitor::EndDecl() { | |
| 62 decl_stack_.pop_back(); | |
| 63 } | |
| 64 | |
| 65 void CheckIPCVisitor::VisitTemplateSpecializationType( | |
| 66 TemplateSpecializationType* spec) { | |
| 67 ValidateCheckedTuple(spec); | |
| 68 } | |
| 69 | |
| 70 void CheckIPCVisitor::VisitCallExpr(CallExpr* call_expr) { | |
| 71 ValidateWriteParam(call_expr); | |
| 72 } | |
| 73 | |
| 74 bool 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. | |
| 86 bool 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. | |
| 98 bool 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. | |
| 133 bool 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; | |
| 141 for (unsigned i = 0; i != spec->getNumArgs(); ++i) { | |
| 142 const TemplateArgument& arg = spec->getArg(i); | |
| 143 CheckDetails details; | |
| 144 if (CheckTemplateArgument(arg, &details)) { | |
| 145 continue; | |
| 146 } | |
| 147 | |
| 148 valid = false; | |
| 149 | |
| 150 auto* parent_decl = GetParentDecl<Decl>(); | |
| 151 ReportCheckError( | |
| 152 details, | |
| 153 parent_decl ? parent_decl->getLocStart() : SourceLocation(), | |
| 154 error_tuple_bad_type_); | |
| 155 } | |
| 156 | |
| 157 return valid; | |
| 158 } | |
| 159 | |
| 160 template <typename T> | |
| 161 const T* CheckIPCVisitor::GetParentDecl() const { | |
| 162 for (auto i = decl_stack_.rbegin(); i != decl_stack_.rend(); ++i) { | |
| 163 if (auto* parent = dyn_cast_or_null<T>(*i)) { | |
| 164 return parent; | |
| 165 } | |
| 166 } | |
| 167 return nullptr; | |
| 168 } | |
| 169 | |
| 170 | |
| 171 bool CheckIPCVisitor::IsBlacklistedType(QualType type) const { | |
| 172 return context_->hasSameUnqualifiedType(type, context_->LongTy) || | |
| 173 context_->hasSameUnqualifiedType(type, context_->UnsignedLongTy); | |
| 174 } | |
| 175 | |
| 176 bool CheckIPCVisitor::IsBlacklistedTypedef(const TypedefNameDecl* tdef) const { | |
| 177 return blacklisted_typedefs_.find(tdef->getName()) != | |
| 178 blacklisted_typedefs_.end(); | |
| 179 } | |
| 180 | |
| 181 // Checks that integer type is allowed (not blacklisted). | |
| 182 bool CheckIPCVisitor::CheckIntegerType(QualType type, | |
| 183 CheckDetails* details) const { | |
| 184 bool seen_typedef = false; | |
| 185 while (true) { | |
| 186 details->exit_type = type; | |
| 187 | |
| 188 if (auto* tdef = dyn_cast<TypedefType>(type)) { | |
| 189 if (IsBlacklistedTypedef(tdef->getDecl())) { | |
| 190 return false; | |
| 191 } | |
| 192 details->typedefs.push_back(tdef); | |
| 193 seen_typedef = true; | |
| 194 } | |
| 195 | |
| 196 QualType desugared_type = | |
| 197 type->getLocallyUnqualifiedSingleStepDesugaredType(); | |
| 198 if (desugared_type == type) { | |
| 199 break; | |
| 200 } | |
| 201 | |
| 202 type = desugared_type; | |
| 203 } | |
| 204 | |
| 205 return seen_typedef || !IsBlacklistedType(type); | |
| 206 } | |
| 207 | |
| 208 // Checks that |type| is allowed (not blacklisted), recursively visiting | |
| 209 // template specializations. | |
| 210 bool CheckIPCVisitor::CheckType(QualType type, CheckDetails* details) const { | |
| 211 if (type->isReferenceType()) { | |
| 212 type = type->getPointeeType(); | |
| 213 } | |
| 214 type = type.getLocalUnqualifiedType(); | |
| 215 | |
| 216 if (details->entry_type.isNull()) { | |
| 217 details->entry_type = type; | |
| 218 } | |
| 219 | |
| 220 if (type->isIntegerType()) { | |
| 221 return CheckIntegerType(type, details); | |
| 222 } | |
| 223 | |
| 224 while (true) { | |
| 225 if (auto* spec = dyn_cast<TemplateSpecializationType>(type)) { | |
| 226 for (const TemplateArgument& arg: *spec) { | |
| 227 if (!CheckTemplateArgument(arg, details)) { | |
| 228 return false; | |
| 229 } | |
| 230 } | |
| 231 return true; | |
| 232 } | |
| 233 | |
| 234 if (auto* record = dyn_cast<RecordType>(type)) { | |
| 235 if (auto* spec = dyn_cast<ClassTemplateSpecializationDecl>( | |
| 236 record->getDecl())) { | |
| 237 const TemplateArgumentList& args = spec->getTemplateArgs(); | |
| 238 for (unsigned i = 0; i != args.size(); ++i) { | |
| 239 if (!CheckTemplateArgument(args[i], details)) { | |
| 240 return false; | |
| 241 } | |
| 242 } | |
| 243 } | |
| 244 return true; | |
| 245 } | |
| 246 | |
| 247 if (auto* tdef = dyn_cast<TypedefType>(type)) { | |
| 248 details->typedefs.push_back(tdef); | |
| 249 } | |
| 250 | |
| 251 QualType desugared_type = | |
| 252 type->getLocallyUnqualifiedSingleStepDesugaredType(); | |
| 253 if (desugared_type == type) { | |
| 254 break; | |
| 255 } | |
| 256 | |
| 257 type = desugared_type; | |
| 258 } | |
| 259 | |
| 260 return true; | |
| 261 } | |
| 262 | |
| 263 bool CheckIPCVisitor::CheckTemplateArgument(const TemplateArgument& arg, | |
| 264 CheckDetails* details) const { | |
| 265 return arg.getKind() != TemplateArgument::Type || | |
| 266 CheckType(arg.getAsType(), details); | |
| 267 } | |
| 268 | |
| 269 void CheckIPCVisitor::ReportCheckError(const CheckDetails& details, | |
| 270 SourceLocation loc, | |
| 271 unsigned error) { | |
| 272 DiagnosticsEngine& diagnostics = compiler_.getDiagnostics(); | |
| 273 | |
| 274 std::string entry_type = details.entry_type.getAsString(); | |
| 275 std::string exit_type = details.exit_type.getAsString(); | |
| 276 | |
| 277 std::string via; | |
| 278 if (entry_type != exit_type) { | |
| 279 via = " via '" + entry_type + "'"; | |
| 280 } | |
| 281 diagnostics.Report(loc, error) << exit_type << via; | |
| 282 | |
| 283 for (const TypedefType* tdef: details.typedefs) { | |
| 284 diagnostics.Report(tdef->getDecl()->getLocation(), note_see_here_); | |
| 285 } | |
| 286 } | |
| 287 | |
| 288 } // namespace chrome_checker | |
| OLD | NEW |