]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
Vendor import of clang trunk r338150:
[FreeBSD/FreeBSD.git] / lib / StaticAnalyzer / Checkers / DynamicTypeChecker.cpp
1 //== DynamicTypeChecker.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 checker looks for cases where the dynamic type of an object is unrelated
11 // to its static type. The type information utilized by this check is collected
12 // by the DynamicTypePropagation checker. This check does not report any type
13 // error for ObjC Generic types, in order to avoid duplicate erros from the
14 // ObjC Generics checker. This checker is not supposed to modify the program
15 // state, it is just the observer of the type information provided by other
16 // checkers.
17 //
18 //===----------------------------------------------------------------------===//
19
20 #include "ClangSACheckers.h"
21 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
22 #include "clang/StaticAnalyzer/Core/Checker.h"
23 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
24 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
25 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
26 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
27 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
28
29 using namespace clang;
30 using namespace ento;
31
32 namespace {
33 class DynamicTypeChecker : public Checker<check::PostStmt<ImplicitCastExpr>> {
34   mutable std::unique_ptr<BugType> BT;
35   void initBugType() const {
36     if (!BT)
37       BT.reset(
38           new BugType(this, "Dynamic and static type mismatch", "Type Error"));
39   }
40
41   class DynamicTypeBugVisitor : public BugReporterVisitor {
42   public:
43     DynamicTypeBugVisitor(const MemRegion *Reg) : Reg(Reg) {}
44
45     void Profile(llvm::FoldingSetNodeID &ID) const override {
46       static int X = 0;
47       ID.AddPointer(&X);
48       ID.AddPointer(Reg);
49     }
50
51     std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
52                                                    const ExplodedNode *PrevN,
53                                                    BugReporterContext &BRC,
54                                                    BugReport &BR) override;
55
56   private:
57     // The tracked region.
58     const MemRegion *Reg;
59   };
60
61   void reportTypeError(QualType DynamicType, QualType StaticType,
62                        const MemRegion *Reg, const Stmt *ReportedNode,
63                        CheckerContext &C) const;
64
65 public:
66   void checkPostStmt(const ImplicitCastExpr *CE, CheckerContext &C) const;
67 };
68 }
69
70 void DynamicTypeChecker::reportTypeError(QualType DynamicType,
71                                          QualType StaticType,
72                                          const MemRegion *Reg,
73                                          const Stmt *ReportedNode,
74                                          CheckerContext &C) const {
75   initBugType();
76   SmallString<192> Buf;
77   llvm::raw_svector_ostream OS(Buf);
78   OS << "Object has a dynamic type '";
79   QualType::print(DynamicType.getTypePtr(), Qualifiers(), OS, C.getLangOpts(),
80                   llvm::Twine());
81   OS << "' which is incompatible with static type '";
82   QualType::print(StaticType.getTypePtr(), Qualifiers(), OS, C.getLangOpts(),
83                   llvm::Twine());
84   OS << "'";
85   std::unique_ptr<BugReport> R(
86       new BugReport(*BT, OS.str(), C.generateNonFatalErrorNode()));
87   R->markInteresting(Reg);
88   R->addVisitor(llvm::make_unique<DynamicTypeBugVisitor>(Reg));
89   R->addRange(ReportedNode->getSourceRange());
90   C.emitReport(std::move(R));
91 }
92
93 std::shared_ptr<PathDiagnosticPiece>
94 DynamicTypeChecker::DynamicTypeBugVisitor::VisitNode(const ExplodedNode *N,
95                                                      const ExplodedNode *PrevN,
96                                                      BugReporterContext &BRC,
97                                                      BugReport &BR) {
98   ProgramStateRef State = N->getState();
99   ProgramStateRef StatePrev = PrevN->getState();
100
101   DynamicTypeInfo TrackedType = getDynamicTypeInfo(State, Reg);
102   DynamicTypeInfo TrackedTypePrev = getDynamicTypeInfo(StatePrev, Reg);
103   if (!TrackedType.isValid())
104     return nullptr;
105
106   if (TrackedTypePrev.isValid() &&
107       TrackedTypePrev.getType() == TrackedType.getType())
108     return nullptr;
109
110   // Retrieve the associated statement.
111   const Stmt *S = PathDiagnosticLocation::getStmt(N);
112   if (!S)
113     return nullptr;
114
115   const LangOptions &LangOpts = BRC.getASTContext().getLangOpts();
116
117   SmallString<256> Buf;
118   llvm::raw_svector_ostream OS(Buf);
119   OS << "Type '";
120   QualType::print(TrackedType.getType().getTypePtr(), Qualifiers(), OS,
121                   LangOpts, llvm::Twine());
122   OS << "' is inferred from ";
123
124   if (const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
125     OS << "explicit cast (from '";
126     QualType::print(ExplicitCast->getSubExpr()->getType().getTypePtr(),
127                     Qualifiers(), OS, LangOpts, llvm::Twine());
128     OS << "' to '";
129     QualType::print(ExplicitCast->getType().getTypePtr(), Qualifiers(), OS,
130                     LangOpts, llvm::Twine());
131     OS << "')";
132   } else if (const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
133     OS << "implicit cast (from '";
134     QualType::print(ImplicitCast->getSubExpr()->getType().getTypePtr(),
135                     Qualifiers(), OS, LangOpts, llvm::Twine());
136     OS << "' to '";
137     QualType::print(ImplicitCast->getType().getTypePtr(), Qualifiers(), OS,
138                     LangOpts, llvm::Twine());
139     OS << "')";
140   } else {
141     OS << "this context";
142   }
143
144   // Generate the extra diagnostic.
145   PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
146                              N->getLocationContext());
147   return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
148                                                     nullptr);
149 }
150
151 static bool hasDefinition(const ObjCObjectPointerType *ObjPtr) {
152   const ObjCInterfaceDecl *Decl = ObjPtr->getInterfaceDecl();
153   if (!Decl)
154     return false;
155
156   return Decl->getDefinition();
157 }
158
159 // TODO: consider checking explicit casts?
160 void DynamicTypeChecker::checkPostStmt(const ImplicitCastExpr *CE,
161                                        CheckerContext &C) const {
162   // TODO: C++ support.
163   if (CE->getCastKind() != CK_BitCast)
164     return;
165
166   const MemRegion *Region = C.getSVal(CE).getAsRegion();
167   if (!Region)
168     return;
169
170   ProgramStateRef State = C.getState();
171   DynamicTypeInfo DynTypeInfo = getDynamicTypeInfo(State, Region);
172
173   if (!DynTypeInfo.isValid())
174     return;
175
176   QualType DynType = DynTypeInfo.getType();
177   QualType StaticType = CE->getType();
178
179   const auto *DynObjCType = DynType->getAs<ObjCObjectPointerType>();
180   const auto *StaticObjCType = StaticType->getAs<ObjCObjectPointerType>();
181
182   if (!DynObjCType || !StaticObjCType)
183     return;
184
185   if (!hasDefinition(DynObjCType) || !hasDefinition(StaticObjCType))
186     return;
187
188   ASTContext &ASTCtxt = C.getASTContext();
189
190   // Strip kindeofness to correctly detect subtyping relationships.
191   DynObjCType = DynObjCType->stripObjCKindOfTypeAndQuals(ASTCtxt);
192   StaticObjCType = StaticObjCType->stripObjCKindOfTypeAndQuals(ASTCtxt);
193
194   // Specialized objects are handled by the generics checker.
195   if (StaticObjCType->isSpecialized())
196     return;
197
198   if (ASTCtxt.canAssignObjCInterfaces(StaticObjCType, DynObjCType))
199     return;
200
201   if (DynTypeInfo.canBeASubClass() &&
202       ASTCtxt.canAssignObjCInterfaces(DynObjCType, StaticObjCType))
203     return;
204
205   reportTypeError(DynType, StaticType, Region, CE, C);
206 }
207
208 void ento::registerDynamicTypeChecker(CheckerManager &mgr) {
209   mgr.registerChecker<DynamicTypeChecker>();
210 }