Coverage Report

Created: 2019-07-24 05:18

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