brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.6 KiB · eeaccf9 Raw
189 lines · cpp
1//=======- MemoryUnsafeCastChecker.cpp -------------------------*- C++ -*-==//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines MemoryUnsafeCast checker, which checks for casts from a10// base type to a derived type.11//===----------------------------------------------------------------------===//12 13#include "clang/ASTMatchers/ASTMatchFinder.h"14#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"15#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"16#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"17#include "clang/StaticAnalyzer/Core/Checker.h"18#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"19 20using namespace clang;21using namespace ento;22using namespace ast_matchers;23 24namespace {25static constexpr const char *const BaseNode = "BaseNode";26static constexpr const char *const DerivedNode = "DerivedNode";27static constexpr const char *const FromCastNode = "FromCast";28static constexpr const char *const ToCastNode = "ToCast";29static constexpr const char *const WarnRecordDecl = "WarnRecordDecl";30 31class MemoryUnsafeCastChecker : public Checker<check::ASTCodeBody> {32  BugType BT{this, "Unsafe cast", "WebKit coding guidelines"};33 34public:35  void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,36                        BugReporter &BR) const;37};38} // end namespace39 40static void emitDiagnostics(const BoundNodes &Nodes, BugReporter &BR,41                            AnalysisDeclContext *ADC,42                            const MemoryUnsafeCastChecker *Checker,43                            const BugType &BT) {44  const auto *CE = Nodes.getNodeAs<CastExpr>(WarnRecordDecl);45  const NamedDecl *Base = Nodes.getNodeAs<NamedDecl>(BaseNode);46  const NamedDecl *Derived = Nodes.getNodeAs<NamedDecl>(DerivedNode);47  assert(CE && Base && Derived);48 49  std::string Diagnostics;50  llvm::raw_string_ostream OS(Diagnostics);51  OS << "Unsafe cast from base type '" << Base->getNameAsString()52     << "' to derived type '" << Derived->getNameAsString() << "'";53  PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),54                               BR.getSourceManager());55  auto Report = std::make_unique<BasicBugReport>(BT, OS.str(), BSLoc);56  Report->addRange(CE->getSourceRange());57  BR.emitReport(std::move(Report));58}59 60static void emitDiagnosticsUnrelated(const BoundNodes &Nodes, BugReporter &BR,61                                     AnalysisDeclContext *ADC,62                                     const MemoryUnsafeCastChecker *Checker,63                                     const BugType &BT) {64  const auto *CE = Nodes.getNodeAs<CastExpr>(WarnRecordDecl);65  const NamedDecl *FromCast = Nodes.getNodeAs<NamedDecl>(FromCastNode);66  const NamedDecl *ToCast = Nodes.getNodeAs<NamedDecl>(ToCastNode);67  assert(CE && FromCast && ToCast);68 69  std::string Diagnostics;70  llvm::raw_string_ostream OS(Diagnostics);71  OS << "Unsafe cast from type '" << FromCast->getNameAsString()72     << "' to an unrelated type '" << ToCast->getNameAsString() << "'";73  PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),74                               BR.getSourceManager());75  auto Report = std::make_unique<BasicBugReport>(BT, OS.str(), BSLoc);76  Report->addRange(CE->getSourceRange());77  BR.emitReport(std::move(Report));78}79 80namespace clang {81namespace ast_matchers {82AST_MATCHER_P(StringLiteral, mentionsBoundType, std::string, BindingID) {83  return Builder->removeBindings([this, &Node](const BoundNodesMap &Nodes) {84    const auto &BN = Nodes.getNode(this->BindingID);85    if (const auto *ND = BN.get<NamedDecl>()) {86      return ND->getName() != Node.getString();87    }88    return true;89  });90}91} // end namespace ast_matchers92} // end namespace clang93 94static decltype(auto) hasTypePointingTo(DeclarationMatcher DeclM) {95  return hasType(pointerType(pointee(hasDeclaration(DeclM))));96}97 98void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl *D,99                                               AnalysisManager &AM,100                                               BugReporter &BR) const {101 102  AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D);103 104  // Match downcasts from base type to derived type and warn105  auto MatchExprPtr = allOf(106      hasSourceExpression(hasTypePointingTo(cxxRecordDecl().bind(BaseNode))),107      hasTypePointingTo(cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode)))108                            .bind(DerivedNode)),109      unless(anyOf(hasSourceExpression(cxxThisExpr()),110                   hasTypePointingTo(templateTypeParmDecl()))));111  auto MatchExprPtrObjC = allOf(112      hasSourceExpression(ignoringImpCasts(hasType(objcObjectPointerType(113          pointee(hasDeclaration(objcInterfaceDecl().bind(BaseNode))))))),114      ignoringImpCasts(hasType(objcObjectPointerType(pointee(hasDeclaration(115          objcInterfaceDecl(isDerivedFrom(equalsBoundNode(BaseNode)))116              .bind(DerivedNode)))))));117  auto MatchExprRefTypeDef =118      allOf(hasSourceExpression(hasType(hasUnqualifiedDesugaredType(recordType(119                hasDeclaration(decl(cxxRecordDecl().bind(BaseNode))))))),120            hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(121                decl(cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode)))122                         .bind(DerivedNode)))))),123            unless(anyOf(hasSourceExpression(hasDescendant(cxxThisExpr())),124                         hasType(templateTypeParmDecl()))));125 126  auto ExplicitCast = explicitCastExpr(anyOf(MatchExprPtr, MatchExprRefTypeDef,127                                             MatchExprPtrObjC))128                          .bind(WarnRecordDecl);129  auto Cast = stmt(ExplicitCast);130 131  auto Matches =132      match(stmt(forEachDescendant(Cast)), *D->getBody(), AM.getASTContext());133  for (BoundNodes Match : Matches)134    emitDiagnostics(Match, BR, ADC, this, BT);135 136  // Match casts between unrelated types and warn137  auto MatchExprPtrUnrelatedTypes = allOf(138      hasSourceExpression(139          hasTypePointingTo(cxxRecordDecl().bind(FromCastNode))),140      hasTypePointingTo(cxxRecordDecl().bind(ToCastNode)),141      unless(anyOf(hasTypePointingTo(cxxRecordDecl(142                       isSameOrDerivedFrom(equalsBoundNode(FromCastNode)))),143                   hasSourceExpression(hasTypePointingTo(cxxRecordDecl(144                       isSameOrDerivedFrom(equalsBoundNode(ToCastNode))))))));145  auto MatchExprPtrObjCUnrelatedTypes = allOf(146      hasSourceExpression(ignoringImpCasts(hasType(objcObjectPointerType(147          pointee(hasDeclaration(objcInterfaceDecl().bind(FromCastNode))))))),148      ignoringImpCasts(hasType(objcObjectPointerType(149          pointee(hasDeclaration(objcInterfaceDecl().bind(ToCastNode)))))),150      unless(anyOf(151          ignoringImpCasts(hasType(152              objcObjectPointerType(pointee(hasDeclaration(objcInterfaceDecl(153                  isSameOrDerivedFrom(equalsBoundNode(FromCastNode)))))))),154          hasSourceExpression(ignoringImpCasts(hasType(155              objcObjectPointerType(pointee(hasDeclaration(objcInterfaceDecl(156                  isSameOrDerivedFrom(equalsBoundNode(ToCastNode))))))))))));157  auto MatchExprRefTypeDefUnrelated = allOf(158      hasSourceExpression(hasType(hasUnqualifiedDesugaredType(recordType(159          hasDeclaration(decl(cxxRecordDecl().bind(FromCastNode))))))),160      hasType(hasUnqualifiedDesugaredType(161          recordType(hasDeclaration(decl(cxxRecordDecl().bind(ToCastNode)))))),162      unless(anyOf(163          hasType(hasUnqualifiedDesugaredType(164              recordType(hasDeclaration(decl(cxxRecordDecl(165                  isSameOrDerivedFrom(equalsBoundNode(FromCastNode)))))))),166          hasSourceExpression(hasType(hasUnqualifiedDesugaredType(167              recordType(hasDeclaration(decl(cxxRecordDecl(168                  isSameOrDerivedFrom(equalsBoundNode(ToCastNode))))))))))));169 170  auto ExplicitCastUnrelated =171      explicitCastExpr(anyOf(MatchExprPtrUnrelatedTypes,172                             MatchExprPtrObjCUnrelatedTypes,173                             MatchExprRefTypeDefUnrelated))174          .bind(WarnRecordDecl);175  auto CastUnrelated = stmt(ExplicitCastUnrelated);176  auto MatchesUnrelatedTypes = match(stmt(forEachDescendant(CastUnrelated)),177                                     *D->getBody(), AM.getASTContext());178  for (BoundNodes Match : MatchesUnrelatedTypes)179    emitDiagnosticsUnrelated(Match, BR, ADC, this, BT);180}181 182void ento::registerMemoryUnsafeCastChecker(CheckerManager &Mgr) {183  Mgr.registerChecker<MemoryUnsafeCastChecker>();184}185 186bool ento::shouldRegisterMemoryUnsafeCastChecker(const CheckerManager &mgr) {187  return true;188}189