"Fossies" - the Fresh Open Source Software Archive

Member "cfe-9.0.0.src/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp" (26 Jan 2019, 4533 Bytes) of package /linux/misc/cfe-9.0.0.src.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "CastToStructChecker.cpp": 8.0.1_vs_9.0.0.

    1 //=== CastToStructChecker.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-exception
    6 //
    7 //===----------------------------------------------------------------------===//
    8 //
    9 // This files defines CastToStructChecker, a builtin checker that checks for
   10 // cast from non-struct pointer to struct pointer and widening struct data cast.
   11 // This check corresponds to CWE-588.
   12 //
   13 //===----------------------------------------------------------------------===//
   14 
   15 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
   16 #include "clang/AST/RecursiveASTVisitor.h"
   17 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
   18 #include "clang/StaticAnalyzer/Core/Checker.h"
   19 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
   20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
   21 
   22 using namespace clang;
   23 using namespace ento;
   24 
   25 namespace {
   26 class CastToStructVisitor : public RecursiveASTVisitor<CastToStructVisitor> {
   27   BugReporter &BR;
   28   const CheckerBase *Checker;
   29   AnalysisDeclContext *AC;
   30 
   31 public:
   32   explicit CastToStructVisitor(BugReporter &B, const CheckerBase *Checker,
   33                                AnalysisDeclContext *A)
   34       : BR(B), Checker(Checker), AC(A) {}
   35   bool VisitCastExpr(const CastExpr *CE);
   36 };
   37 }
   38 
   39 bool CastToStructVisitor::VisitCastExpr(const CastExpr *CE) {
   40   const Expr *E = CE->getSubExpr();
   41   ASTContext &Ctx = AC->getASTContext();
   42   QualType OrigTy = Ctx.getCanonicalType(E->getType());
   43   QualType ToTy = Ctx.getCanonicalType(CE->getType());
   44 
   45   const PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
   46   const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
   47 
   48   if (!ToPTy || !OrigPTy)
   49     return true;
   50 
   51   QualType OrigPointeeTy = OrigPTy->getPointeeType();
   52   QualType ToPointeeTy = ToPTy->getPointeeType();
   53 
   54   if (!ToPointeeTy->isStructureOrClassType())
   55     return true;
   56 
   57   // We allow cast from void*.
   58   if (OrigPointeeTy->isVoidType())
   59     return true;
   60 
   61   // Now the cast-to-type is struct pointer, the original type is not void*.
   62   if (!OrigPointeeTy->isRecordType()) {
   63     SourceRange Sr[1] = {CE->getSourceRange()};
   64     PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);
   65     BR.EmitBasicReport(
   66         AC->getDecl(), Checker, "Cast from non-struct type to struct type",
   67         categories::LogicError, "Casting a non-structure type to a structure "
   68                                 "type and accessing a field can lead to memory "
   69                                 "access errors or data corruption.",
   70         Loc, Sr);
   71   } else {
   72     // Don't warn when size of data is unknown.
   73     const auto *U = dyn_cast<UnaryOperator>(E);
   74     if (!U || U->getOpcode() != UO_AddrOf)
   75       return true;
   76 
   77     // Don't warn for references
   78     const ValueDecl *VD = nullptr;
   79     if (const auto *SE = dyn_cast<DeclRefExpr>(U->getSubExpr()))
   80       VD = SE->getDecl();
   81     else if (const auto *SE = dyn_cast<MemberExpr>(U->getSubExpr()))
   82       VD = SE->getMemberDecl();
   83     if (!VD || VD->getType()->isReferenceType())
   84       return true;
   85 
   86     if (ToPointeeTy->isIncompleteType() ||
   87         OrigPointeeTy->isIncompleteType())
   88       return true;
   89 
   90     // Warn when there is widening cast.
   91     unsigned ToWidth = Ctx.getTypeInfo(ToPointeeTy).Width;
   92     unsigned OrigWidth = Ctx.getTypeInfo(OrigPointeeTy).Width;
   93     if (ToWidth <= OrigWidth)
   94       return true;
   95 
   96     PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);
   97     BR.EmitBasicReport(AC->getDecl(), Checker, "Widening cast to struct type",
   98                        categories::LogicError,
   99                        "Casting data to a larger structure type and accessing "
  100                        "a field can lead to memory access errors or data "
  101                        "corruption.",
  102                        Loc, CE->getSourceRange());
  103   }
  104 
  105   return true;
  106 }
  107 
  108 namespace {
  109 class CastToStructChecker : public Checker<check::ASTCodeBody> {
  110 public:
  111   void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
  112                         BugReporter &BR) const {
  113     CastToStructVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
  114     Visitor.TraverseDecl(const_cast<Decl *>(D));
  115   }
  116 };
  117 } // end anonymous namespace
  118 
  119 void ento::registerCastToStructChecker(CheckerManager &mgr) {
  120   mgr.registerChecker<CastToStructChecker>();
  121 }
  122 
  123 bool ento::shouldRegisterCastToStructChecker(const LangOptions &LO) {
  124   return true;
  125 }