Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
Line
Count
Source (jump to first uncovered line)
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
15
  void initBugType() const {
36
15
    if (!BT)
37
3
      BT.reset(
38
3
          new BugType(this, "Dynamic and static type mismatch", "Type Error"));
39
15
  }
40
41
  class DynamicTypeBugVisitor
42
      : public BugReporterVisitorImpl<DynamicTypeBugVisitor> {
43
  public:
44
15
    DynamicTypeBugVisitor(const MemRegion *Reg) : Reg(Reg) {}
45
46
17
    void Profile(llvm::FoldingSetNodeID &ID) const override {
47
17
      static int X = 0;
48
17
      ID.AddPointer(&X);
49
17
      ID.AddPointer(Reg);
50
17
    }
51
52
    std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
53
                                                   const ExplodedNode *PrevN,
54
                                                   BugReporterContext &BRC,
55
                                                   BugReport &BR) override;
56
57
  private:
58
    // The tracked region.
59
    const MemRegion *Reg;
60
  };
61
62
  void reportTypeError(QualType DynamicType, QualType StaticType,
63
                       const MemRegion *Reg, const Stmt *ReportedNode,
64
                       CheckerContext &C) const;
65
66
public:
67
  void checkPostStmt(const ImplicitCastExpr *CE, CheckerContext &C) const;
68
};
69
}
70
71
void DynamicTypeChecker::reportTypeError(QualType DynamicType,
72
                                         QualType StaticType,
73
                                         const MemRegion *Reg,
74
                                         const Stmt *ReportedNode,
75
15
                                         CheckerContext &C) const {
76
15
  initBugType();
77
15
  SmallString<192> Buf;
78
15
  llvm::raw_svector_ostream OS(Buf);
79
15
  OS << "Object has a dynamic type '";
80
15
  QualType::print(DynamicType.getTypePtr(), Qualifiers(), OS, C.getLangOpts(),
81
15
                  llvm::Twine());
82
15
  OS << "' which is incompatible with static type '";
83
15
  QualType::print(StaticType.getTypePtr(), Qualifiers(), OS, C.getLangOpts(),
84
15
                  llvm::Twine());
85
15
  OS << "'";
86
15
  std::unique_ptr<BugReport> R(
87
15
      new BugReport(*BT, OS.str(), C.generateNonFatalErrorNode()));
88
15
  R->markInteresting(Reg);
89
15
  R->addVisitor(llvm::make_unique<DynamicTypeBugVisitor>(Reg));
90
15
  R->addRange(ReportedNode->getSourceRange());
91
15
  C.emitReport(std::move(R));
92
15
}
93
94
std::shared_ptr<PathDiagnosticPiece>
95
DynamicTypeChecker::DynamicTypeBugVisitor::VisitNode(const ExplodedNode *N,
96
                                                     const ExplodedNode *PrevN,
97
                                                     BugReporterContext &BRC,
98
1.09k
                                                     BugReport &BR) {
99
1.09k
  ProgramStateRef State = N->getState();
100
1.09k
  ProgramStateRef StatePrev = PrevN->getState();
101
1.09k
102
1.09k
  DynamicTypeInfo TrackedType = getDynamicTypeInfo(State, Reg);
103
1.09k
  DynamicTypeInfo TrackedTypePrev = getDynamicTypeInfo(StatePrev, Reg);
104
1.09k
  if (!TrackedType.isValid())
105
0
    return nullptr;
106
1.09k
107
1.09k
  
if (1.09k
TrackedTypePrev.isValid() &&
108
1.09k
      TrackedTypePrev.getType() == TrackedType.getType())
109
1.07k
    return nullptr;
110
19
111
19
  // Retrieve the associated statement.
112
19
  const Stmt *S = PathDiagnosticLocation::getStmt(N);
113
19
  if (!S)
114
0
    return nullptr;
115
19
116
19
  const LangOptions &LangOpts = BRC.getASTContext().getLangOpts();
117
19
118
19
  SmallString<256> Buf;
119
19
  llvm::raw_svector_ostream OS(Buf);
120
19
  OS << "Type '";
121
19
  QualType::print(TrackedType.getType().getTypePtr(), Qualifiers(), OS,
122
19
                  LangOpts, llvm::Twine());
123
19
  OS << "' is inferred from ";
124
19
125
19
  if (const auto *
ExplicitCast19
= dyn_cast<ExplicitCastExpr>(S)) {
126
0
    OS << "explicit cast (from '";
127
0
    QualType::print(ExplicitCast->getSubExpr()->getType().getTypePtr(),
128
0
                    Qualifiers(), OS, LangOpts, llvm::Twine());
129
0
    OS << "' to '";
130
0
    QualType::print(ExplicitCast->getType().getTypePtr(), Qualifiers(), OS,
131
0
                    LangOpts, llvm::Twine());
132
0
    OS << "')";
133
19
  } else 
if (const auto *19
ImplicitCast19
= dyn_cast<ImplicitCastExpr>(S)) {
134
0
    OS << "implicit cast (from '";
135
0
    QualType::print(ImplicitCast->getSubExpr()->getType().getTypePtr(),
136
0
                    Qualifiers(), OS, LangOpts, llvm::Twine());
137
0
    OS << "' to '";
138
0
    QualType::print(ImplicitCast->getType().getTypePtr(), Qualifiers(), OS,
139
0
                    LangOpts, llvm::Twine());
140
0
    OS << "')";
141
19
  } else {
142
19
    OS << "this context";
143
19
  }
144
1.09k
145
1.09k
  // Generate the extra diagnostic.
146
1.09k
  PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
147
1.09k
                             N->getLocationContext());
148
1.09k
  return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
149
1.09k
                                                    nullptr);
150
1.09k
}
151
152
688
static bool hasDefinition(const ObjCObjectPointerType *ObjPtr) {
153
688
  const ObjCInterfaceDecl *Decl = ObjPtr->getInterfaceDecl();
154
688
  if (!Decl)
155
162
    return false;
156
526
157
526
  return Decl->getDefinition();
158
526
}
159
160
// TODO: consider checking explicit casts?
161
void DynamicTypeChecker::checkPostStmt(const ImplicitCastExpr *CE,
162
7.59k
                                       CheckerContext &C) const {
163
7.59k
  // TODO: C++ support.
164
7.59k
  if (CE->getCastKind() != CK_BitCast)
165
6.95k
    return;
166
640
167
640
  const MemRegion *Region = C.getSVal(CE).getAsRegion();
168
640
  if (!Region)
169
54
    return;
170
586
171
586
  ProgramStateRef State = C.getState();
172
586
  DynamicTypeInfo DynTypeInfo = getDynamicTypeInfo(State, Region);
173
586
174
586
  if (!DynTypeInfo.isValid())
175
0
    return;
176
586
177
586
  QualType DynType = DynTypeInfo.getType();
178
586
  QualType StaticType = CE->getType();
179
586
180
586
  const auto *DynObjCType = DynType->getAs<ObjCObjectPointerType>();
181
586
  const auto *StaticObjCType = StaticType->getAs<ObjCObjectPointerType>();
182
586
183
586
  if (
!DynObjCType || 586
!StaticObjCType362
)
184
236
    return;
185
350
186
350
  
if (350
!hasDefinition(DynObjCType) || 350
!hasDefinition(StaticObjCType)338
)
187
172
    return;
188
178
189
178
  ASTContext &ASTCtxt = C.getASTContext();
190
178
191
178
  // Strip kindeofness to correctly detect subtyping relationships.
192
178
  DynObjCType = DynObjCType->stripObjCKindOfTypeAndQuals(ASTCtxt);
193
178
  StaticObjCType = StaticObjCType->stripObjCKindOfTypeAndQuals(ASTCtxt);
194
178
195
178
  // Specialized objects are handled by the generics checker.
196
178
  if (StaticObjCType->isSpecialized())
197
102
    return;
198
76
199
76
  
if (76
ASTCtxt.canAssignObjCInterfaces(StaticObjCType, DynObjCType)76
)
200
61
    return;
201
15
202
15
  
if (15
DynTypeInfo.canBeASubClass() &&
203
15
      ASTCtxt.canAssignObjCInterfaces(DynObjCType, StaticObjCType))
204
0
    return;
205
15
206
15
  reportTypeError(DynType, StaticType, Region, CE, C);
207
15
}
208
209
67
void ento::registerDynamicTypeChecker(CheckerManager &mgr) {
210
67
  mgr.registerChecker<DynamicTypeChecker>();
211
67
}