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

Unified Diff: tools/clang/plugins/CheckIPCVisitor.cpp

Issue 1810243002: Check for unstable types in IPC messages. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add comment Created 4 years, 8 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/clang/plugins/CheckIPCVisitor.h ('k') | tools/clang/plugins/FindBadConstructsAction.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/clang/plugins/CheckIPCVisitor.cpp
diff --git a/tools/clang/plugins/CheckIPCVisitor.cpp b/tools/clang/plugins/CheckIPCVisitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b123b0130ed1c5dd3d5690476a149a84187271ab
--- /dev/null
+++ b/tools/clang/plugins/CheckIPCVisitor.cpp
@@ -0,0 +1,288 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "CheckIPCVisitor.h"
+
+using namespace clang;
+
+namespace chrome_checker {
+
+namespace {
+
+const char kWriteParamBadType[] =
+ "[chromium-ipc] IPC::WriteParam() is called on blacklisted type '%0'%1.";
+
+const char kTupleBadType[] =
+ "[chromium-ipc] IPC tuple references banned type '%0'%1.";
+
+const char kWriteParamBadSignature[] =
+ "[chromium-ipc] IPC::WriteParam() is expected to have two arguments.";
+
+const char kNoteSeeHere[] =
+ "see here";
+
+} // namespace
+
+CheckIPCVisitor::CheckIPCVisitor(CompilerInstance& compiler)
+ : compiler_(compiler), context_(nullptr) {
+ auto& diagnostics = compiler_.getDiagnostics();
+ error_write_param_bad_type_ = diagnostics.getCustomDiagID(
+ DiagnosticsEngine::Error, kWriteParamBadType);
+ error_tuple_bad_type_ = diagnostics.getCustomDiagID(
+ DiagnosticsEngine::Error, kTupleBadType);
+ error_write_param_bad_signature_ = diagnostics.getCustomDiagID(
+ DiagnosticsEngine::Error, kWriteParamBadSignature);
+ note_see_here_ = diagnostics.getCustomDiagID(
+ DiagnosticsEngine::Note, kNoteSeeHere);
+
+ blacklisted_typedefs_ = llvm::StringSet<>({
+ "intmax_t",
+ "uintmax_t",
+ "intptr_t",
+ "uintptr_t",
+ "wint_t",
+ "size_t",
+ "rsize_t",
+ "ssize_t",
+ "ptrdiff_t",
+ "dev_t",
+ "off_t",
+ "clock_t",
+ "time_t",
+ "suseconds_t"
+ });
+}
+
+void CheckIPCVisitor::BeginDecl(Decl* decl) {
+ decl_stack_.push_back(decl);
+}
+
+void CheckIPCVisitor::EndDecl() {
+ decl_stack_.pop_back();
+}
+
+void CheckIPCVisitor::VisitTemplateSpecializationType(
+ TemplateSpecializationType* spec) {
+ ValidateCheckedTuple(spec);
+}
+
+void CheckIPCVisitor::VisitCallExpr(CallExpr* call_expr) {
+ ValidateWriteParam(call_expr);
+}
+
+bool CheckIPCVisitor::ValidateWriteParam(const CallExpr* call_expr) {
+ const FunctionDecl* callee_decl = call_expr->getDirectCallee();
+ if (!callee_decl ||
+ callee_decl->getQualifiedNameAsString() != "IPC::WriteParam") {
+ return true;
+ }
+
+ return ValidateWriteParamSignature(call_expr) &&
+ ValidateWriteParamArgument(call_expr->getArg(1));
+}
+
+// Checks that IPC::WriteParam() has expected signature.
+bool CheckIPCVisitor::ValidateWriteParamSignature(
+ const CallExpr* call_expr) {
+ if (call_expr->getNumArgs() != 2) {
+ compiler_.getDiagnostics().Report(
+ call_expr->getExprLoc(), error_write_param_bad_signature_);
+ return false;
+ }
+ return true;
+}
+
+// Checks that IPC::WriteParam() argument type is allowed.
+// See CheckType() for specifics.
+bool CheckIPCVisitor::ValidateWriteParamArgument(const Expr* arg_expr) {
+ if (auto* parent_fn_decl = GetParentDecl<FunctionDecl>()) {
+ auto template_kind = parent_fn_decl->getTemplatedKind();
+ if (template_kind != FunctionDecl::TK_NonTemplate &&
+ template_kind != FunctionDecl::TK_FunctionTemplate) {
+ // Skip all specializations - we don't check WriteParam() on dependent
+ // types (typedef info gets lost), and we checked all non-dependent uses
+ // earlier (when we checked the template itself).
+ return true;
+ }
+ }
+
+ QualType arg_type;
+
+ arg_expr = arg_expr->IgnoreImplicit();
+ if (auto* cast_expr = dyn_cast<ExplicitCastExpr>(arg_expr)) {
+ arg_type = cast_expr->getTypeAsWritten();
+ } else {
+ arg_type = arg_expr->getType();
+ }
+
+ CheckDetails details;
+ if (CheckType(arg_type, &details)) {
+ return true;
+ }
+
+ ReportCheckError(details,
+ arg_expr->getExprLoc(),
+ error_write_param_bad_type_);
+
+ return false;
+}
+
+// Checks that IPC::CheckedTuple<> is specialized with allowed types.
+// See CheckType() above for specifics.
+bool CheckIPCVisitor::ValidateCheckedTuple(
+ const TemplateSpecializationType* spec) {
+ TemplateDecl* decl = spec->getTemplateName().getAsTemplateDecl();
+ if (!decl || decl->getQualifiedNameAsString() != "IPC::CheckedTuple") {
+ return true;
+ }
+
+ bool valid = true;
+ for (unsigned i = 0; i != spec->getNumArgs(); ++i) {
+ const TemplateArgument& arg = spec->getArg(i);
+ CheckDetails details;
+ if (CheckTemplateArgument(arg, &details)) {
+ continue;
+ }
+
+ valid = false;
+
+ auto* parent_decl = GetParentDecl<Decl>();
+ ReportCheckError(
+ details,
+ parent_decl ? parent_decl->getLocStart() : SourceLocation(),
+ error_tuple_bad_type_);
+ }
+
+ return valid;
+}
+
+template <typename T>
+const T* CheckIPCVisitor::GetParentDecl() const {
+ for (auto i = decl_stack_.rbegin(); i != decl_stack_.rend(); ++i) {
+ if (auto* parent = dyn_cast_or_null<T>(*i)) {
+ return parent;
+ }
+ }
+ return nullptr;
+}
+
+
+bool CheckIPCVisitor::IsBlacklistedType(QualType type) const {
+ return context_->hasSameUnqualifiedType(type, context_->LongTy) ||
+ context_->hasSameUnqualifiedType(type, context_->UnsignedLongTy);
+}
+
+bool CheckIPCVisitor::IsBlacklistedTypedef(const TypedefNameDecl* tdef) const {
+ return blacklisted_typedefs_.find(tdef->getName()) !=
+ blacklisted_typedefs_.end();
+}
+
+// Checks that integer type is allowed (not blacklisted).
+bool CheckIPCVisitor::CheckIntegerType(QualType type,
+ CheckDetails* details) const {
+ bool seen_typedef = false;
+ while (true) {
+ details->exit_type = type;
+
+ if (auto* tdef = dyn_cast<TypedefType>(type)) {
+ if (IsBlacklistedTypedef(tdef->getDecl())) {
+ return false;
+ }
+ details->typedefs.push_back(tdef);
+ seen_typedef = true;
+ }
+
+ QualType desugared_type =
+ type->getLocallyUnqualifiedSingleStepDesugaredType();
+ if (desugared_type == type) {
+ break;
+ }
+
+ type = desugared_type;
+ }
+
+ return seen_typedef || !IsBlacklistedType(type);
+}
+
+// Checks that |type| is allowed (not blacklisted), recursively visiting
+// template specializations.
+bool CheckIPCVisitor::CheckType(QualType type, CheckDetails* details) const {
+ if (type->isReferenceType()) {
+ type = type->getPointeeType();
+ }
+ type = type.getLocalUnqualifiedType();
+
+ if (details->entry_type.isNull()) {
+ details->entry_type = type;
+ }
+
+ if (type->isIntegerType()) {
+ return CheckIntegerType(type, details);
+ }
+
+ while (true) {
+ if (auto* spec = dyn_cast<TemplateSpecializationType>(type)) {
+ for (const TemplateArgument& arg: *spec) {
+ if (!CheckTemplateArgument(arg, details)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (auto* record = dyn_cast<RecordType>(type)) {
+ if (auto* spec = dyn_cast<ClassTemplateSpecializationDecl>(
+ record->getDecl())) {
+ const TemplateArgumentList& args = spec->getTemplateArgs();
+ for (unsigned i = 0; i != args.size(); ++i) {
+ if (!CheckTemplateArgument(args[i], details)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ if (auto* tdef = dyn_cast<TypedefType>(type)) {
+ details->typedefs.push_back(tdef);
+ }
+
+ QualType desugared_type =
+ type->getLocallyUnqualifiedSingleStepDesugaredType();
+ if (desugared_type == type) {
+ break;
+ }
+
+ type = desugared_type;
+ }
+
+ return true;
+}
+
+bool CheckIPCVisitor::CheckTemplateArgument(const TemplateArgument& arg,
+ CheckDetails* details) const {
+ return arg.getKind() != TemplateArgument::Type ||
+ CheckType(arg.getAsType(), details);
+}
+
+void CheckIPCVisitor::ReportCheckError(const CheckDetails& details,
+ SourceLocation loc,
+ unsigned error) {
+ DiagnosticsEngine& diagnostics = compiler_.getDiagnostics();
+
+ std::string entry_type = details.entry_type.getAsString();
+ std::string exit_type = details.exit_type.getAsString();
+
+ std::string via;
+ if (entry_type != exit_type) {
+ via = " via '" + entry_type + "'";
+ }
+ diagnostics.Report(loc, error) << exit_type << via;
+
+ for (const TypedefType* tdef: details.typedefs) {
+ diagnostics.Report(tdef->getDecl()->getLocation(), note_see_here_);
+ }
+}
+
+} // namespace chrome_checker
« no previous file with comments | « tools/clang/plugins/CheckIPCVisitor.h ('k') | tools/clang/plugins/FindBadConstructsAction.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698