Coverage Report

Created: 2020-03-31 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/DynamicType.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- DynamicType.cpp - Dynamic type related APIs --------------*- 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 file defines APIs that track and query dynamic type information. This
10
//  information can be used to devirtualize calls during the symbolic execution
11
//  or do type checking.
12
//
13
//===----------------------------------------------------------------------===//
14
15
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
16
#include "clang/Basic/JsonSupport.h"
17
#include "clang/Basic/LLVM.h"
18
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
19
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
20
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
21
#include "llvm/Support/Casting.h"
22
#include "llvm/Support/raw_ostream.h"
23
#include <cassert>
24
25
/// The GDM component containing the dynamic type info. This is a map from a
26
/// symbol to its most likely type.
27
REGISTER_MAP_WITH_PROGRAMSTATE(DynamicTypeMap, const clang::ento::MemRegion *,
28
                               clang::ento::DynamicTypeInfo)
29
30
/// A set factory of dynamic cast informations.
31
REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(CastSet, clang::ento::DynamicCastInfo)
32
33
/// A map from symbols to cast informations.
34
REGISTER_MAP_WITH_PROGRAMSTATE(DynamicCastMap, const clang::ento::MemRegion *,
35
                               CastSet)
36
37
namespace clang {
38
namespace ento {
39
40
7.59k
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR) {
41
7.59k
  MR = MR->StripCasts();
42
7.59k
43
7.59k
  // Look up the dynamic type in the GDM.
44
7.59k
  if (const DynamicTypeInfo *DTI = State->get<DynamicTypeMap>(MR))
45
2.62k
    return *DTI;
46
4.96k
47
4.96k
  // Otherwise, fall back to what we know about the region.
48
4.96k
  if (const auto *TR = dyn_cast<TypedRegion>(MR))
49
356
    return DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false);
50
4.61k
51
4.61k
  if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) {
52
4.61k
    SymbolRef Sym = SR->getSymbol();
53
4.61k
    return DynamicTypeInfo(Sym->getType());
54
4.61k
  }
55
1
56
1
  return {};
57
1
}
58
59
const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State,
60
37
                                             const MemRegion *MR) {
61
37
  return State->get<DynamicTypeMap>(MR);
62
37
}
63
64
const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
65
                                          const MemRegion *MR,
66
                                          QualType CastFromTy,
67
60
                                          QualType CastToTy) {
68
60
  const auto *Lookup = State->get<DynamicCastMap>().lookup(MR);
69
60
  if (!Lookup)
70
36
    return nullptr;
71
24
72
24
  for (const DynamicCastInfo &Cast : *Lookup)
73
34
    if (Cast.equals(CastFromTy, CastToTy))
74
6
      return &Cast;
75
24
76
24
  
return nullptr18
;
77
24
}
78
79
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
80
9.38k
                                   DynamicTypeInfo NewTy) {
81
9.38k
  State = State->set<DynamicTypeMap>(MR->StripCasts(), NewTy);
82
9.38k
  assert(State);
83
9.38k
  return State;
84
9.38k
}
85
86
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
87
8.69k
                                   QualType NewTy, bool CanBeSubClassed) {
88
8.69k
  return setDynamicTypeInfo(State, MR, DynamicTypeInfo(NewTy, CanBeSubClassed));
89
8.69k
}
90
91
ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State,
92
                                          const MemRegion *MR,
93
                                          QualType CastFromTy,
94
                                          QualType CastToTy,
95
54
                                          bool CastSucceeds) {
96
54
  if (!MR)
97
0
    return State;
98
54
99
54
  if (CastSucceeds) {
100
30
    assert((CastToTy->isAnyPointerType() || CastToTy->isReferenceType()) &&
101
30
           "DynamicTypeInfo should always be a pointer.");
102
30
    State = State->set<DynamicTypeMap>(MR, CastToTy);
103
30
  }
104
54
105
54
  DynamicCastInfo::CastResult ResultKind =
106
54
      CastSucceeds ? 
DynamicCastInfo::CastResult::Success30
107
54
                   : 
DynamicCastInfo::CastResult::Failure24
;
108
54
109
54
  CastSet::Factory &F = State->get_context<CastSet>();
110
54
111
54
  const CastSet *TempSet = State->get<DynamicCastMap>(MR);
112
54
  CastSet Set = TempSet ? 
*TempSet18
:
F.getEmptySet()36
;
113
54
114
54
  Set = F.add(Set, {CastFromTy, CastToTy, ResultKind});
115
54
  State = State->set<DynamicCastMap>(MR, Set);
116
54
117
54
  assert(State);
118
54
  return State;
119
54
}
120
121
template <typename MapTy>
122
ProgramStateRef removeDead(ProgramStateRef State, const MapTy &Map,
123
481k
                           SymbolReaper &SR) {
124
481k
  for (const auto &Elem : Map)
125
1.01M
    if (!SR.isLiveRegion(Elem.first))
126
861k
      State = State->remove<DynamicCastMap>(Elem.first);
127
481k
128
481k
  return State;
129
481k
}
llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const> clang::ento::removeDead<llvm::ImmutableMap<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo, llvm::ImutKeyValueInfo<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo> > >(llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>, llvm::ImmutableMap<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo, llvm::ImutKeyValueInfo<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo> > const&, clang::ento::SymbolReaper&)
Line
Count
Source
123
481k
                           SymbolReaper &SR) {
124
481k
  for (const auto &Elem : Map)
125
1.01M
    if (!SR.isLiveRegion(Elem.first))
126
861k
      State = State->remove<DynamicCastMap>(Elem.first);
127
481k
128
481k
  return State;
129
481k
}
Unexecuted instantiation: llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const> clang::ento::removeDead<llvm::ImmutableMap<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> >, llvm::ImutKeyValueInfo<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> > > > >(llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>, llvm::ImmutableMap<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> >, llvm::ImutKeyValueInfo<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> > > > const&, clang::ento::SymbolReaper&)
130
131
481k
ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR) {
132
481k
  return removeDead(State, State->get<DynamicTypeMap>(), SR);
133
481k
}
134
135
0
ProgramStateRef removeDeadCasts(ProgramStateRef State, SymbolReaper &SR) {
136
0
  return removeDead(State, State->get<DynamicCastMap>(), SR);
137
0
}
138
139
static void printDynamicTypesJson(raw_ostream &Out, ProgramStateRef State,
140
                                  const char *NL, unsigned int Space,
141
113
                                  bool IsDot) {
142
113
  Indent(Out, Space, IsDot) << "\"dynamic_types\": ";
143
113
144
113
  const DynamicTypeMapTy &Map = State->get<DynamicTypeMap>();
145
113
  if (Map.isEmpty()) {
146
104
    Out << "null," << NL;
147
104
    return;
148
104
  }
149
9
150
9
  ++Space;
151
9
  Out << '[' << NL;
152
18
  for (DynamicTypeMapTy::iterator I = Map.begin(); I != Map.end(); 
++I9
) {
153
9
    const MemRegion *MR = I->first;
154
9
    const DynamicTypeInfo &DTI = I->second;
155
9
    Indent(Out, Space, IsDot)
156
9
        << "{ \"region\": \"" << MR << "\", \"dyn_type\": ";
157
9
    if (!DTI.isValid()) {
158
0
      Out << "null";
159
9
    } else {
160
9
      Out << '\"' << DTI.getType()->getPointeeType().getAsString()
161
9
          << "\", \"sub_classable\": "
162
9
          << (DTI.canBeASubClass() ? 
"true"1
:
"false"8
);
163
9
    }
164
9
    Out << " }";
165
9
166
9
    if (std::next(I) != Map.end())
167
0
      Out << ',';
168
9
    Out << NL;
169
9
  }
170
9
171
9
  --Space;
172
9
  Indent(Out, Space, IsDot) << "]," << NL;
173
9
}
174
175
static void printDynamicCastsJson(raw_ostream &Out, ProgramStateRef State,
176
                                  const char *NL, unsigned int Space,
177
113
                                  bool IsDot) {
178
113
  Indent(Out, Space, IsDot) << "\"dynamic_casts\": ";
179
113
180
113
  const DynamicCastMapTy &Map = State->get<DynamicCastMap>();
181
113
  if (Map.isEmpty()) {
182
111
    Out << "null," << NL;
183
111
    return;
184
111
  }
185
2
186
2
  ++Space;
187
2
  Out << '[' << NL;
188
4
  for (DynamicCastMapTy::iterator I = Map.begin(); I != Map.end(); 
++I2
) {
189
2
    const MemRegion *MR = I->first;
190
2
    const CastSet &Set = I->second;
191
2
192
2
    Indent(Out, Space, IsDot) << "{ \"region\": \"" << MR << "\", \"casts\": ";
193
2
    if (Set.isEmpty()) {
194
0
      Out << "null ";
195
2
    } else {
196
2
      ++Space;
197
2
      Out << '[' << NL;
198
6
      for (CastSet::iterator SI = Set.begin(); SI != Set.end(); 
++SI4
) {
199
4
        Indent(Out, Space, IsDot)
200
4
            << "{ \"from\": \"" << SI->from().getAsString() << "\", \"to\": \""
201
4
            << SI->to().getAsString() << "\", \"kind\": \""
202
4
            << (SI->succeeds() ? 
"success"1
:
"fail"3
) << "\" }";
203
4
204
4
        if (std::next(SI) != Set.end())
205
2
          Out << ',';
206
4
        Out << NL;
207
4
      }
208
2
      --Space;
209
2
      Indent(Out, Space, IsDot) << ']';
210
2
    }
211
2
    Out << '}';
212
2
213
2
    if (std::next(I) != Map.end())
214
0
      Out << ',';
215
2
    Out << NL;
216
2
  }
217
2
218
2
  --Space;
219
2
  Indent(Out, Space, IsDot) << "]," << NL;
220
2
}
221
222
void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State,
223
113
                              const char *NL, unsigned int Space, bool IsDot) {
224
113
  printDynamicTypesJson(Out, State, NL, Space, IsDot);
225
113
  printDynamicCastsJson(Out, State, NL, Space, IsDot);
226
113
}
227
228
} // namespace ento
229
} // namespace clang