CastToStructChecker.cpp 4.3 KB

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