xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp (revision d99bd55a5e092774214ba31fc5a871bfc31e711c)
1 //=== CastToStructChecker.cpp - Fixed address usage checker ----*- 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.
12 // This check corresponds to CWE-588.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "clang/StaticAnalyzer/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
18 #include "ExprEngineInternalChecks.h"
19 
20 using namespace clang;
21 using namespace ento;
22 
23 namespace {
24 class CastToStructChecker
25   : public CheckerVisitor<CastToStructChecker> {
26   BuiltinBug *BT;
27 public:
28   CastToStructChecker() : BT(0) {}
29   static void *getTag();
30   void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
31 };
32 }
33 
34 void *CastToStructChecker::getTag() {
35   static int x;
36   return &x;
37 }
38 
39 void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
40                                            const CastExpr *CE) {
41   const Expr *E = CE->getSubExpr();
42   ASTContext &Ctx = C.getASTContext();
43   QualType OrigTy = Ctx.getCanonicalType(E->getType());
44   QualType ToTy = Ctx.getCanonicalType(CE->getType());
45 
46   PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
47   PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
48 
49   if (!ToPTy || !OrigPTy)
50     return;
51 
52   QualType OrigPointeeTy = OrigPTy->getPointeeType();
53   QualType ToPointeeTy = ToPTy->getPointeeType();
54 
55   if (!ToPointeeTy->isStructureOrClassType())
56     return;
57 
58   // We allow cast from void*.
59   if (OrigPointeeTy->isVoidType())
60     return;
61 
62   // Now the cast-to-type is struct pointer, the original type is not void*.
63   if (!OrigPointeeTy->isRecordType()) {
64     if (ExplodedNode *N = C.generateNode()) {
65       if (!BT)
66         BT = new BuiltinBug("Cast from non-struct type to struct type",
67                             "Casting a non-structure type to a structure type "
68                             "and accessing a field can lead to memory access "
69                             "errors or data corruption.");
70       RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
71       R->addRange(CE->getSourceRange());
72       C.EmitReport(R);
73     }
74   }
75 }
76 
77 void ento::RegisterCastToStructChecker(ExprEngine &Eng) {
78   Eng.registerCheck(new CastToStructChecker());
79 }
80