[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

Devin Coughlin via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 19 09:50:10 PST 2024


================
@@ -0,0 +1,132 @@
+//=======- MemoryUnsafeCastChecker.cpp -------------------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines MemoryUnsafeCast checker, which checks for casts from a
+// base type to a derived type.
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+
+using namespace clang;
+using namespace ento;
+using namespace ast_matchers;
+
+namespace {
+static constexpr const char *const BaseNode = "BaseNode";
+static constexpr const char *const DerivedNode = "DerivedNode";
+static constexpr const char *const WarnRecordDecl = "WarnRecordDecl";
+
+class MemoryUnsafeCastChecker : public Checker<check::ASTCodeBody> {
+  BugType BT{this, "Unsafe cast", "WebKit coding guidelines"};
+public:
+  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
+                        BugReporter &BR) const;
+};
+}  // end namespace
+
+static void emitDiagnostics(const BoundNodes &Nodes, BugReporter &BR,
+                            AnalysisDeclContext *ADC,
+                            const MemoryUnsafeCastChecker *Checker) {
+  const auto *CE = Nodes.getNodeAs<CastExpr>(WarnRecordDecl);
+  const NamedDecl *Base = Nodes.getNodeAs<NamedDecl>(BaseNode);
+  const NamedDecl *Derived = Nodes.getNodeAs<NamedDecl>(DerivedNode);
+  assert(CE && Base && Derived);
+
+  std::string Diagnostics;
+  llvm::raw_string_ostream OS(Diagnostics);
+  OS << "Unsafe cast from base type '" << Base->getNameAsString()
+     << "' to derived type '" << Derived->getNameAsString() << "'";
+
+  BR.EmitBasicReport(
+      ADC->getDecl(), Checker,
+      /*Name=*/"OSObject C-Style Cast", categories::SecurityError,
+      Diagnostics,
+      PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), ADC),
+      CE->getSourceRange());
+}
+
+namespace clang {
+namespace ast_matchers {
+AST_MATCHER_P(StringLiteral, mentionsBoundType, std::string, BindingID) {
+  return Builder->removeBindings([this, &Node](const BoundNodesMap &Nodes) {
+    const auto &BN = Nodes.getNode(this->BindingID);
+    if (const auto *ND = BN.get<NamedDecl>()) {
+      return ND->getName() != Node.getString();
+    }
+    return true;
+  });
+}
+} // end namespace ast_matchers
+} // end namespace clang
+
+static decltype(auto) hasTypePointingTo(DeclarationMatcher DeclM) {
+  return hasType(pointerType(pointee(hasDeclaration(DeclM))));
+}
+
+void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl *D,
+                                               AnalysisManager &AM,
+                                               BugReporter &BR) const {
+
+  AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D);
+
+  auto MatchExprPtr = allOf(
+      hasSourceExpression(hasTypePointingTo(cxxRecordDecl().bind(BaseNode))),
+      hasTypePointingTo(cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode)))
----------------
devincoughlin wrote:

Does this also catch cross casts? For example, if A and B both derive from D and A is cast to B, do we want to reject that? (And similarly if A and B don't have a common base?)

https://github.com/llvm/llvm-project/pull/114606


More information about the cfe-commits mailing list