Path: blob/main/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
35266 views
//=== CastToStructChecker.cpp ----------------------------------*- C++ -*--===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This files defines CastToStructChecker, a builtin checker that checks for9// cast from non-struct pointer to struct pointer and widening struct data cast.10// This check corresponds to CWE-588.11//12//===----------------------------------------------------------------------===//1314#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"15#include "clang/AST/RecursiveASTVisitor.h"16#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"17#include "clang/StaticAnalyzer/Core/Checker.h"18#include "clang/StaticAnalyzer/Core/CheckerManager.h"19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"2021using namespace clang;22using namespace ento;2324namespace {25class CastToStructVisitor : public RecursiveASTVisitor<CastToStructVisitor> {26BugReporter &BR;27const CheckerBase *Checker;28AnalysisDeclContext *AC;2930public:31explicit CastToStructVisitor(BugReporter &B, const CheckerBase *Checker,32AnalysisDeclContext *A)33: BR(B), Checker(Checker), AC(A) {}34bool VisitCastExpr(const CastExpr *CE);35};36}3738bool CastToStructVisitor::VisitCastExpr(const CastExpr *CE) {39const Expr *E = CE->getSubExpr();40ASTContext &Ctx = AC->getASTContext();41QualType OrigTy = Ctx.getCanonicalType(E->getType());42QualType ToTy = Ctx.getCanonicalType(CE->getType());4344const PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());45const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());4647if (!ToPTy || !OrigPTy)48return true;4950QualType OrigPointeeTy = OrigPTy->getPointeeType();51QualType ToPointeeTy = ToPTy->getPointeeType();5253if (!ToPointeeTy->isStructureOrClassType())54return true;5556// We allow cast from void*.57if (OrigPointeeTy->isVoidType())58return true;5960// Now the cast-to-type is struct pointer, the original type is not void*.61if (!OrigPointeeTy->isRecordType()) {62SourceRange Sr[1] = {CE->getSourceRange()};63PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);64BR.EmitBasicReport(65AC->getDecl(), Checker, "Cast from non-struct type to struct type",66categories::LogicError, "Casting a non-structure type to a structure "67"type and accessing a field can lead to memory "68"access errors or data corruption.",69Loc, Sr);70} else {71// Don't warn when size of data is unknown.72const auto *U = dyn_cast<UnaryOperator>(E);73if (!U || U->getOpcode() != UO_AddrOf)74return true;7576// Don't warn for references77const ValueDecl *VD = nullptr;78if (const auto *SE = dyn_cast<DeclRefExpr>(U->getSubExpr()))79VD = SE->getDecl();80else if (const auto *SE = dyn_cast<MemberExpr>(U->getSubExpr()))81VD = SE->getMemberDecl();82if (!VD || VD->getType()->isReferenceType())83return true;8485if (ToPointeeTy->isIncompleteType() ||86OrigPointeeTy->isIncompleteType())87return true;8889// Warn when there is widening cast.90unsigned ToWidth = Ctx.getTypeInfo(ToPointeeTy).Width;91unsigned OrigWidth = Ctx.getTypeInfo(OrigPointeeTy).Width;92if (ToWidth <= OrigWidth)93return true;9495PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);96BR.EmitBasicReport(AC->getDecl(), Checker, "Widening cast to struct type",97categories::LogicError,98"Casting data to a larger structure type and accessing "99"a field can lead to memory access errors or data "100"corruption.",101Loc, CE->getSourceRange());102}103104return true;105}106107namespace {108class CastToStructChecker : public Checker<check::ASTCodeBody> {109public:110void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,111BugReporter &BR) const {112CastToStructVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));113Visitor.TraverseDecl(const_cast<Decl *>(D));114}115};116} // end anonymous namespace117118void ento::registerCastToStructChecker(CheckerManager &mgr) {119mgr.registerChecker<CastToStructChecker>();120}121122bool ento::shouldRegisterCastToStructChecker(const CheckerManager &mgr) {123return true;124}125126127