diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 21:29:30 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 21:29:30 +0000 | 
| commit | 442906470441699a0cffb2c475ee2fa6e6e57515 (patch) | |
| tree | bbbef432354ebeb711fa2c51fe72874e072a8be9 /contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp | |
| parent | d88c1a5a572cdb661c111098831fa526e933756f (diff) | |
| parent | bab175ec4b075c8076ba14c762900392533f6ee4 (diff) | |
Notes
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp | 87 | 
1 files changed, 65 insertions, 22 deletions
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp index fa7841356efb..16a475ae9dd2 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp @@ -1,4 +1,4 @@ -//=== CastToStructChecker.cpp - Fixed address usage checker ----*- C++ -*--===// +//=== CastToStructChecker.cpp ----------------------------------*- C++ -*--===//  //  //                     The LLVM Compiler Infrastructure  // @@ -8,12 +8,13 @@  //===----------------------------------------------------------------------===//  //  // This files defines CastToStructChecker, a builtin checker that checks for -// cast from non-struct pointer to struct pointer. +// cast from non-struct pointer to struct pointer and widening struct data cast.  // This check corresponds to CWE-588.  //  //===----------------------------------------------------------------------===//  #include "ClangSACheckers.h" +#include "clang/AST/RecursiveASTVisitor.h"  #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"  #include "clang/StaticAnalyzer/Core/Checker.h"  #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -23,18 +24,22 @@ using namespace clang;  using namespace ento;  namespace { -class CastToStructChecker : public Checker< check::PreStmt<CastExpr> > { -  mutable std::unique_ptr<BuiltinBug> BT; +class CastToStructVisitor : public RecursiveASTVisitor<CastToStructVisitor> { +  BugReporter &BR; +  const CheckerBase *Checker; +  AnalysisDeclContext *AC;  public: -  void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; +  explicit CastToStructVisitor(BugReporter &B, const CheckerBase *Checker, +                               AnalysisDeclContext *A) +      : BR(B), Checker(Checker), AC(A) {} +  bool VisitCastExpr(const CastExpr *CE);  };  } -void CastToStructChecker::checkPreStmt(const CastExpr *CE, -                                       CheckerContext &C) const { +bool CastToStructVisitor::VisitCastExpr(const CastExpr *CE) {    const Expr *E = CE->getSubExpr(); -  ASTContext &Ctx = C.getASTContext(); +  ASTContext &Ctx = AC->getASTContext();    QualType OrigTy = Ctx.getCanonicalType(E->getType());    QualType ToTy = Ctx.getCanonicalType(CE->getType()); @@ -42,34 +47,72 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE,    const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());    if (!ToPTy || !OrigPTy) -    return; +    return true;    QualType OrigPointeeTy = OrigPTy->getPointeeType();    QualType ToPointeeTy = ToPTy->getPointeeType();    if (!ToPointeeTy->isStructureOrClassType()) -    return; +    return true;    // We allow cast from void*.    if (OrigPointeeTy->isVoidType()) -    return; +    return true;    // Now the cast-to-type is struct pointer, the original type is not void*.    if (!OrigPointeeTy->isRecordType()) { -    if (ExplodedNode *N = C.generateNonFatalErrorNode()) { -      if (!BT) -        BT.reset( -            new BuiltinBug(this, "Cast from non-struct type to struct type", -                           "Casting a non-structure type to a structure type " -                           "and accessing a field can lead to memory access " -                           "errors or data corruption.")); -      auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N); -      R->addRange(CE->getSourceRange()); -      C.emitReport(std::move(R)); -    } +    SourceRange Sr[1] = {CE->getSourceRange()}; +    PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC); +    BR.EmitBasicReport( +        AC->getDecl(), Checker, "Cast from non-struct type to struct type", +        categories::LogicError, "Casting a non-structure type to a structure " +                                "type and accessing a field can lead to memory " +                                "access errors or data corruption.", +        Loc, Sr); +  } else { +    // Don't warn when size of data is unknown. +    const auto *U = dyn_cast<UnaryOperator>(E); +    if (!U || U->getOpcode() != UO_AddrOf) +      return true; + +    // Don't warn for references +    const ValueDecl *VD = nullptr; +    if (const auto *SE = dyn_cast<DeclRefExpr>(U->getSubExpr())) +      VD = dyn_cast<ValueDecl>(SE->getDecl()); +    else if (const auto *SE = dyn_cast<MemberExpr>(U->getSubExpr())) +      VD = SE->getMemberDecl(); +    if (!VD || VD->getType()->isReferenceType()) +      return true; + +    // Warn when there is widening cast. +    unsigned ToWidth = Ctx.getTypeInfo(ToPointeeTy).Width; +    unsigned OrigWidth = Ctx.getTypeInfo(OrigPointeeTy).Width; +    if (ToWidth <= OrigWidth) +      return true; + +    PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC); +    BR.EmitBasicReport(AC->getDecl(), Checker, "Widening cast to struct type", +                       categories::LogicError, +                       "Casting data to a larger structure type and accessing " +                       "a field can lead to memory access errors or data " +                       "corruption.", +                       Loc, CE->getSourceRange());    } + +  return true;  } +namespace { +class CastToStructChecker : public Checker<check::ASTCodeBody> { +public: +  void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr, +                        BugReporter &BR) const { +    CastToStructVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D)); +    Visitor.TraverseDecl(const_cast<Decl *>(D)); +  } +}; +} // end anonymous namespace +  void ento::registerCastToStructChecker(CheckerManager &mgr) {    mgr.registerChecker<CastToStructChecker>();  }  | 
