113264ebeSDaniel Marjamaki //=== CastToStructChecker.cpp ----------------------------------*- C++ -*--===//
2d99bd55aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d99bd55aSTed Kremenek //
7d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
8d99bd55aSTed Kremenek //
9d99bd55aSTed Kremenek // This files defines CastToStructChecker, a builtin checker that checks for
1013264ebeSDaniel Marjamaki // cast from non-struct pointer to struct pointer and widening struct data cast.
11d99bd55aSTed Kremenek // This check corresponds to CWE-588.
12d99bd55aSTed Kremenek //
13d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
14d99bd55aSTed Kremenek 
1576a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
1613264ebeSDaniel Marjamaki #include "clang/AST/RecursiveASTVisitor.h"
173a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
186a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h"
19507ff53eSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20dff865d1SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21d99bd55aSTed Kremenek 
22d99bd55aSTed Kremenek using namespace clang;
23d99bd55aSTed Kremenek using namespace ento;
24d99bd55aSTed Kremenek 
25d99bd55aSTed Kremenek namespace {
2613264ebeSDaniel Marjamaki class CastToStructVisitor : public RecursiveASTVisitor<CastToStructVisitor> {
2713264ebeSDaniel Marjamaki   BugReporter &BR;
2813264ebeSDaniel Marjamaki   const CheckerBase *Checker;
2913264ebeSDaniel Marjamaki   AnalysisDeclContext *AC;
30dff865d1SArgyrios Kyrtzidis 
31d99bd55aSTed Kremenek public:
CastToStructVisitor(BugReporter & B,const CheckerBase * Checker,AnalysisDeclContext * A)3213264ebeSDaniel Marjamaki   explicit CastToStructVisitor(BugReporter &B, const CheckerBase *Checker,
3313264ebeSDaniel Marjamaki                                AnalysisDeclContext *A)
3413264ebeSDaniel Marjamaki       : BR(B), Checker(Checker), AC(A) {}
3513264ebeSDaniel Marjamaki   bool VisitCastExpr(const CastExpr *CE);
36d99bd55aSTed Kremenek };
37d99bd55aSTed Kremenek }
38d99bd55aSTed Kremenek 
VisitCastExpr(const CastExpr * CE)3913264ebeSDaniel Marjamaki bool CastToStructVisitor::VisitCastExpr(const CastExpr *CE) {
40d99bd55aSTed Kremenek   const Expr *E = CE->getSubExpr();
4113264ebeSDaniel Marjamaki   ASTContext &Ctx = AC->getASTContext();
42d99bd55aSTed Kremenek   QualType OrigTy = Ctx.getCanonicalType(E->getType());
43d99bd55aSTed Kremenek   QualType ToTy = Ctx.getCanonicalType(CE->getType());
44d99bd55aSTed Kremenek 
45424cec97SJohn McCall   const PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
46424cec97SJohn McCall   const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
47d99bd55aSTed Kremenek 
48d99bd55aSTed Kremenek   if (!ToPTy || !OrigPTy)
4913264ebeSDaniel Marjamaki     return true;
50d99bd55aSTed Kremenek 
51d99bd55aSTed Kremenek   QualType OrigPointeeTy = OrigPTy->getPointeeType();
52d99bd55aSTed Kremenek   QualType ToPointeeTy = ToPTy->getPointeeType();
53d99bd55aSTed Kremenek 
54d99bd55aSTed Kremenek   if (!ToPointeeTy->isStructureOrClassType())
5513264ebeSDaniel Marjamaki     return true;
56d99bd55aSTed Kremenek 
57d99bd55aSTed Kremenek   // We allow cast from void*.
58d99bd55aSTed Kremenek   if (OrigPointeeTy->isVoidType())
5913264ebeSDaniel Marjamaki     return true;
60d99bd55aSTed Kremenek 
61d99bd55aSTed Kremenek   // Now the cast-to-type is struct pointer, the original type is not void*.
62d99bd55aSTed Kremenek   if (!OrigPointeeTy->isRecordType()) {
6313264ebeSDaniel Marjamaki     SourceRange Sr[1] = {CE->getSourceRange()};
6413264ebeSDaniel Marjamaki     PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);
6513264ebeSDaniel Marjamaki     BR.EmitBasicReport(
6613264ebeSDaniel Marjamaki         AC->getDecl(), Checker, "Cast from non-struct type to struct type",
6713264ebeSDaniel Marjamaki         categories::LogicError, "Casting a non-structure type to a structure "
6813264ebeSDaniel Marjamaki                                 "type and accessing a field can lead to memory "
6913264ebeSDaniel Marjamaki                                 "access errors or data corruption.",
7013264ebeSDaniel Marjamaki         Loc, Sr);
7113264ebeSDaniel Marjamaki   } else {
7213264ebeSDaniel Marjamaki     // Don't warn when size of data is unknown.
7313264ebeSDaniel Marjamaki     const auto *U = dyn_cast<UnaryOperator>(E);
7413264ebeSDaniel Marjamaki     if (!U || U->getOpcode() != UO_AddrOf)
7513264ebeSDaniel Marjamaki       return true;
7613264ebeSDaniel Marjamaki 
7713264ebeSDaniel Marjamaki     // Don't warn for references
7813264ebeSDaniel Marjamaki     const ValueDecl *VD = nullptr;
7913264ebeSDaniel Marjamaki     if (const auto *SE = dyn_cast<DeclRefExpr>(U->getSubExpr()))
8000f70bd9SGeorge Burgess IV       VD = SE->getDecl();
8113264ebeSDaniel Marjamaki     else if (const auto *SE = dyn_cast<MemberExpr>(U->getSubExpr()))
8213264ebeSDaniel Marjamaki       VD = SE->getMemberDecl();
8313264ebeSDaniel Marjamaki     if (!VD || VD->getType()->isReferenceType())
8413264ebeSDaniel Marjamaki       return true;
8513264ebeSDaniel Marjamaki 
86cf715bd3SDaniel Marjamaki     if (ToPointeeTy->isIncompleteType() ||
87cf715bd3SDaniel Marjamaki         OrigPointeeTy->isIncompleteType())
88cf715bd3SDaniel Marjamaki       return true;
89cf715bd3SDaniel Marjamaki 
9013264ebeSDaniel Marjamaki     // Warn when there is widening cast.
9113264ebeSDaniel Marjamaki     unsigned ToWidth = Ctx.getTypeInfo(ToPointeeTy).Width;
9213264ebeSDaniel Marjamaki     unsigned OrigWidth = Ctx.getTypeInfo(OrigPointeeTy).Width;
9313264ebeSDaniel Marjamaki     if (ToWidth <= OrigWidth)
9413264ebeSDaniel Marjamaki       return true;
9513264ebeSDaniel Marjamaki 
9613264ebeSDaniel Marjamaki     PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);
9713264ebeSDaniel Marjamaki     BR.EmitBasicReport(AC->getDecl(), Checker, "Widening cast to struct type",
9813264ebeSDaniel Marjamaki                        categories::LogicError,
9913264ebeSDaniel Marjamaki                        "Casting data to a larger structure type and accessing "
10013264ebeSDaniel Marjamaki                        "a field can lead to memory access errors or data "
10113264ebeSDaniel Marjamaki                        "corruption.",
10213264ebeSDaniel Marjamaki                        Loc, CE->getSourceRange());
103d99bd55aSTed Kremenek   }
10413264ebeSDaniel Marjamaki 
10513264ebeSDaniel Marjamaki   return true;
106d99bd55aSTed Kremenek }
10713264ebeSDaniel Marjamaki 
10813264ebeSDaniel Marjamaki namespace {
10913264ebeSDaniel Marjamaki class CastToStructChecker : public Checker<check::ASTCodeBody> {
11013264ebeSDaniel Marjamaki public:
checkASTCodeBody(const Decl * D,AnalysisManager & Mgr,BugReporter & BR) const11113264ebeSDaniel Marjamaki   void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
11213264ebeSDaniel Marjamaki                         BugReporter &BR) const {
11313264ebeSDaniel Marjamaki     CastToStructVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
11413264ebeSDaniel Marjamaki     Visitor.TraverseDecl(const_cast<Decl *>(D));
115d99bd55aSTed Kremenek   }
11613264ebeSDaniel Marjamaki };
11713264ebeSDaniel Marjamaki } // end anonymous namespace
118d99bd55aSTed Kremenek 
registerCastToStructChecker(CheckerManager & mgr)119507ff53eSArgyrios Kyrtzidis void ento::registerCastToStructChecker(CheckerManager &mgr) {
120dff865d1SArgyrios Kyrtzidis   mgr.registerChecker<CastToStructChecker>();
121507ff53eSArgyrios Kyrtzidis }
122058a7a45SKristof Umann 
shouldRegisterCastToStructChecker(const CheckerManager & mgr)123*bda3dd0dSKirstóf Umann bool ento::shouldRegisterCastToStructChecker(const CheckerManager &mgr) {
124058a7a45SKristof Umann   return true;
125058a7a45SKristof Umann }
126