brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.4 KiB · 3e87ad0 Raw
126 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This files defines CastToStructChecker, a builtin checker that checks for10// 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/AST/DynamicRecursiveASTVisitor.h"16#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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 22using namespace clang;23using namespace ento;24 25namespace {26class CastToStructVisitor : public DynamicRecursiveASTVisitor {27  BugReporter &BR;28  const CheckerBase *Checker;29  AnalysisDeclContext *AC;30 31public:32  explicit CastToStructVisitor(BugReporter &B, const CheckerBase *Checker,33                               AnalysisDeclContext *A)34      : BR(B), Checker(Checker), AC(A) {}35  bool VisitCastExpr(CastExpr *CE) override;36};37}38 39bool CastToStructVisitor::VisitCastExpr(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 references78    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 108namespace {109class CastToStructChecker : public Checker<check::ASTCodeBody> {110public: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 namespace118 119void ento::registerCastToStructChecker(CheckerManager &mgr) {120  mgr.registerChecker<CastToStructChecker>();121}122 123bool ento::shouldRegisterCastToStructChecker(const CheckerManager &mgr) {124  return true;125}126