blob: a0cebd6ab856292cb7d3e52632df2c671a11425b [file] [log] [blame]
Csaba Dabis693936a2019-07-10 00:20:03 +00001//===- CastValueChecker - Model implementation of custom RTTIs --*- 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//
Csaba Dabis0202c352019-08-22 00:20:36 +00009// This defines CastValueChecker which models casts of custom RTTIs.
10//
11// TODO list:
12// - It only allows one succesful cast between two types however in the wild
13// the object could be casted to multiple types.
14// - It needs to check the most likely type information from the dynamic type
15// map to increase precision of dynamic casting.
Csaba Dabis693936a2019-07-10 00:20:03 +000016//
17//===----------------------------------------------------------------------===//
18
Csaba Dabis4d716002019-08-22 02:57:59 +000019#include "clang/AST/DeclTemplate.h"
Csaba Dabis693936a2019-07-10 00:20:03 +000020#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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/CheckerContext.h"
Csaba Dabis0202c352019-08-22 00:20:36 +000025#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
Csaba Dabis693936a2019-07-10 00:20:03 +000026#include "llvm/ADT/Optional.h"
Csaba Dabiscf229d52019-08-09 02:24:42 +000027#include <utility>
Csaba Dabis693936a2019-07-10 00:20:03 +000028
29using namespace clang;
30using namespace ento;
31
32namespace {
33class CastValueChecker : public Checker<eval::Call> {
Csaba Dabis4d716002019-08-22 02:57:59 +000034 enum class CallKind { Function, Method, InstanceOf };
Csaba Dabiscf229d52019-08-09 02:24:42 +000035
Csaba Dabis693936a2019-07-10 00:20:03 +000036 using CastCheck =
Csaba Dabis0202c352019-08-22 00:20:36 +000037 std::function<void(const CastValueChecker *, const CallEvent &Call,
Csaba Dabis693936a2019-07-10 00:20:03 +000038 DefinedOrUnknownSVal, CheckerContext &)>;
39
40public:
Csaba Dabiscf229d52019-08-09 02:24:42 +000041 // We have five cases to evaluate a cast:
Csaba Dabis0202c352019-08-22 00:20:36 +000042 // 1) The parameter is non-null, the return value is non-null.
43 // 2) The parameter is non-null, the return value is null.
44 // 3) The parameter is null, the return value is null.
Csaba Dabis693936a2019-07-10 00:20:03 +000045 // cast: 1; dyn_cast: 1, 2; cast_or_null: 1, 3; dyn_cast_or_null: 1, 2, 3.
Csaba Dabiscf229d52019-08-09 02:24:42 +000046 //
Csaba Dabis0202c352019-08-22 00:20:36 +000047 // 4) castAs: Has no parameter, the return value is non-null.
48 // 5) getAs: Has no parameter, the return value is null or non-null.
Csaba Dabis4d716002019-08-22 02:57:59 +000049 //
50 // We have two cases to check the parameter is an instance of the given type.
51 // 1) isa: The parameter is non-null, returns boolean.
52 // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean.
Csaba Dabis693936a2019-07-10 00:20:03 +000053 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
54
55private:
Csaba Dabiscf229d52019-08-09 02:24:42 +000056 // These are known in the LLVM project. The pairs are in the following form:
57 // {{{namespace, call}, argument-count}, {callback, kind}}
Csaba Dabis0202c352019-08-22 00:20:36 +000058 const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = {
Csaba Dabiscf229d52019-08-09 02:24:42 +000059 {{{"llvm", "cast"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000060 {&CastValueChecker::evalCast, CallKind::Function}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000061 {{{"llvm", "dyn_cast"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000062 {&CastValueChecker::evalDynCast, CallKind::Function}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000063 {{{"llvm", "cast_or_null"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000064 {&CastValueChecker::evalCastOrNull, CallKind::Function}},
Csaba Dabis693936a2019-07-10 00:20:03 +000065 {{{"llvm", "dyn_cast_or_null"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000066 {&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000067 {{{"clang", "castAs"}, 0},
Csaba Dabis0202c352019-08-22 00:20:36 +000068 {&CastValueChecker::evalCastAs, CallKind::Method}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000069 {{{"clang", "getAs"}, 0},
Csaba Dabis4d716002019-08-22 02:57:59 +000070 {&CastValueChecker::evalGetAs, CallKind::Method}},
71 {{{"llvm", "isa"}, 1},
72 {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
73 {{{"llvm", "isa_and_nonnull"}, 1},
74 {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
Csaba Dabis693936a2019-07-10 00:20:03 +000075
Csaba Dabis0202c352019-08-22 00:20:36 +000076 void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000077 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000078 void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000079 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000080 void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000081 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000082 void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000083 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000084 void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +000085 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000086 void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +000087 CheckerContext &C) const;
Csaba Dabis4d716002019-08-22 02:57:59 +000088 void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
89 CheckerContext &C) const;
90 void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
91 CheckerContext &C) const;
Csaba Dabis693936a2019-07-10 00:20:03 +000092};
93} // namespace
94
Csaba Dabis0202c352019-08-22 00:20:36 +000095static bool isInfeasibleCast(const DynamicCastInfo *CastInfo,
96 bool CastSucceeds) {
97 if (!CastInfo)
98 return false;
99
100 return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds();
101}
102
103static const NoteTag *getNoteTag(CheckerContext &C,
104 const DynamicCastInfo *CastInfo,
105 QualType CastToTy, const Expr *Object,
106 bool CastSucceeds, bool IsKnownCast) {
107 std::string CastToName =
Artem Dergachev62a76d02019-08-23 03:24:01 +0000108 CastInfo ? CastInfo->to()->getPointeeCXXRecordDecl()->getNameAsString()
109 : CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
Csaba Dabis0202c352019-08-22 00:20:36 +0000110 Object = Object->IgnoreParenImpCasts();
Csaba Dabis693936a2019-07-10 00:20:03 +0000111
Csaba Dabiscf229d52019-08-09 02:24:42 +0000112 return C.getNoteTag(
Csaba Dabis22dc44f2019-08-22 01:41:06 +0000113 [=]() -> std::string {
Csaba Dabis693936a2019-07-10 00:20:03 +0000114 SmallString<128> Msg;
115 llvm::raw_svector_ostream Out(Msg);
116
Csaba Dabis0202c352019-08-22 00:20:36 +0000117 if (!IsKnownCast)
118 Out << "Assuming ";
Csaba Dabiscf229d52019-08-09 02:24:42 +0000119
Csaba Dabis0202c352019-08-22 00:20:36 +0000120 if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
121 Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
122 } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
123 Out << (IsKnownCast ? "Field '" : "field '")
124 << ME->getMemberDecl()->getNameAsString() << '\'';
125 } else {
126 Out << (IsKnownCast ? "The object" : "the object");
127 }
128
129 Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName
130 << '\'';
Csaba Dabiscf229d52019-08-09 02:24:42 +0000131
Csaba Dabis693936a2019-07-10 00:20:03 +0000132 return Out.str();
133 },
134 /*IsPrunable=*/true);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000135}
Csaba Dabis693936a2019-07-10 00:20:03 +0000136
Csaba Dabis0202c352019-08-22 00:20:36 +0000137//===----------------------------------------------------------------------===//
138// Main logic to evaluate a cast.
139//===----------------------------------------------------------------------===//
140
141static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
142 CheckerContext &C, bool IsNonNullParam,
143 bool IsNonNullReturn,
144 bool IsCheckedCast = false) {
145 ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
146 if (!State)
147 return;
148
149 const Expr *Object;
150 QualType CastFromTy;
Artem Dergachev62a76d02019-08-23 03:24:01 +0000151 QualType CastToTy = Call.getResultType();
Csaba Dabis0202c352019-08-22 00:20:36 +0000152
153 if (Call.getNumArgs() > 0) {
154 Object = Call.getArgExpr(0);
Artem Dergachev62a76d02019-08-23 03:24:01 +0000155 CastFromTy = Call.parameters()[0]->getType();
Csaba Dabis0202c352019-08-22 00:20:36 +0000156 } else {
157 Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
Artem Dergachev62a76d02019-08-23 03:24:01 +0000158 CastFromTy = Object->getType();
Csaba Dabis0202c352019-08-22 00:20:36 +0000159 }
160
161 const MemRegion *MR = DV.getAsRegion();
162 const DynamicCastInfo *CastInfo =
163 getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
164
165 // We assume that every checked cast succeeds.
166 bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
167 if (!CastSucceeds) {
168 if (CastInfo)
169 CastSucceeds = IsNonNullReturn && CastInfo->succeeds();
170 else
171 CastSucceeds = IsNonNullReturn;
172 }
173
174 // Check for infeasible casts.
175 if (isInfeasibleCast(CastInfo, CastSucceeds)) {
176 C.generateSink(State, C.getPredecessor());
177 return;
178 }
179
180 // Store the type and the cast information.
181 bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
182 if (!IsKnownCast || IsCheckedCast)
183 State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
Artem Dergachev62a76d02019-08-23 03:24:01 +0000184 CastSucceeds);
Csaba Dabis0202c352019-08-22 00:20:36 +0000185
186 SVal V = CastSucceeds ? DV : C.getSValBuilder().makeNull();
187 C.addTransition(
188 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
189 getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
Csaba Dabiscf229d52019-08-09 02:24:42 +0000190}
191
Csaba Dabis4d716002019-08-22 02:57:59 +0000192static void addInstanceOfTransition(const CallEvent &Call,
193 DefinedOrUnknownSVal DV,
194 ProgramStateRef State, CheckerContext &C,
195 bool IsInstanceOf) {
196 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
Artem Dergachev62a76d02019-08-23 03:24:01 +0000197 QualType CastFromTy = Call.parameters()[0]->getType();
Csaba Dabis4d716002019-08-22 02:57:59 +0000198 QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType();
Artem Dergachev62a76d02019-08-23 03:24:01 +0000199 if (CastFromTy->isPointerType())
200 CastToTy = C.getASTContext().getPointerType(CastToTy);
201 else if (CastFromTy->isLValueReferenceType() &&
202 CastFromTy.isConstQualified()) {
203 CastToTy.addConst();
204 CastToTy = C.getASTContext().getLValueReferenceType(CastToTy);
205 } else if (CastFromTy->isLValueReferenceType())
206 CastToTy = C.getASTContext().getLValueReferenceType(CastToTy);
207 else if (CastFromTy->isRValueReferenceType())
208 CastToTy = C.getASTContext().getRValueReferenceType(CastToTy);
209 else
210 return;
Csaba Dabis4d716002019-08-22 02:57:59 +0000211
212 const MemRegion *MR = DV.getAsRegion();
213 const DynamicCastInfo *CastInfo =
214 getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
215
216 bool CastSucceeds;
217 if (CastInfo)
218 CastSucceeds = IsInstanceOf && CastInfo->succeeds();
219 else
220 CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
221
222 if (isInfeasibleCast(CastInfo, CastSucceeds)) {
223 C.generateSink(State, C.getPredecessor());
224 return;
225 }
226
227 // Store the type and the cast information.
228 bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
229 if (!IsKnownCast)
230 State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
Artem Dergachev62a76d02019-08-23 03:24:01 +0000231 IsInstanceOf);
Csaba Dabis4d716002019-08-22 02:57:59 +0000232
233 C.addTransition(
234 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
235 C.getSValBuilder().makeTruthVal(CastSucceeds)),
236 getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
237 IsKnownCast));
238}
239
Csaba Dabiscf229d52019-08-09 02:24:42 +0000240//===----------------------------------------------------------------------===//
241// Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null.
242//===----------------------------------------------------------------------===//
243
Csaba Dabis0202c352019-08-22 00:20:36 +0000244static void evalNonNullParamNonNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000245 DefinedOrUnknownSVal DV,
246 CheckerContext &C,
247 bool IsCheckedCast = false) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000248 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
249 /*IsNonNullReturn=*/true, IsCheckedCast);
Csaba Dabis693936a2019-07-10 00:20:03 +0000250}
251
Csaba Dabis0202c352019-08-22 00:20:36 +0000252static void evalNonNullParamNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000253 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000254 CheckerContext &C) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000255 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
256 /*IsNonNullReturn=*/false);
Csaba Dabis693936a2019-07-10 00:20:03 +0000257}
258
Csaba Dabis0202c352019-08-22 00:20:36 +0000259static void evalNullParamNullReturn(const CallEvent &Call,
260 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000261 CheckerContext &C) {
Csaba Dabiscf229d52019-08-09 02:24:42 +0000262 if (ProgramStateRef State = C.getState()->assume(DV, false))
Csaba Dabis0202c352019-08-22 00:20:36 +0000263 C.addTransition(State->BindExpr(Call.getOriginExpr(),
264 C.getLocationContext(),
265 C.getSValBuilder().makeNull(), false),
Csaba Dabiscf229d52019-08-09 02:24:42 +0000266 C.getNoteTag("Assuming null pointer is passed into cast",
267 /*IsPrunable=*/true));
Csaba Dabis693936a2019-07-10 00:20:03 +0000268}
269
Csaba Dabis0202c352019-08-22 00:20:36 +0000270void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000271 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000272 evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
Csaba Dabis693936a2019-07-10 00:20:03 +0000273}
274
Csaba Dabis0202c352019-08-22 00:20:36 +0000275void CastValueChecker::evalDynCast(const CallEvent &Call,
276 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000277 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000278 evalNonNullParamNonNullReturn(Call, DV, C);
279 evalNonNullParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000280}
281
Csaba Dabis0202c352019-08-22 00:20:36 +0000282void CastValueChecker::evalCastOrNull(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000283 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000284 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000285 evalNonNullParamNonNullReturn(Call, DV, C);
286 evalNullParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000287}
288
Csaba Dabis0202c352019-08-22 00:20:36 +0000289void CastValueChecker::evalDynCastOrNull(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000290 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000291 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000292 evalNonNullParamNonNullReturn(Call, DV, C);
293 evalNonNullParamNullReturn(Call, DV, C);
294 evalNullParamNullReturn(Call, DV, C);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000295}
296
297//===----------------------------------------------------------------------===//
298// Evaluating castAs, getAs.
299//===----------------------------------------------------------------------===//
300
Csaba Dabis0202c352019-08-22 00:20:36 +0000301static void evalZeroParamNonNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000302 DefinedOrUnknownSVal DV,
303 CheckerContext &C,
304 bool IsCheckedCast = false) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000305 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
306 /*IsNonNullReturn=*/true, IsCheckedCast);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000307}
308
Csaba Dabis0202c352019-08-22 00:20:36 +0000309static void evalZeroParamNullReturn(const CallEvent &Call,
310 DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000311 CheckerContext &C) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000312 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
313 /*IsNonNullReturn=*/false);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000314}
315
Csaba Dabis0202c352019-08-22 00:20:36 +0000316void CastValueChecker::evalCastAs(const CallEvent &Call,
317 DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000318 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000319 evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000320}
321
Csaba Dabis0202c352019-08-22 00:20:36 +0000322void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000323 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000324 evalZeroParamNonNullReturn(Call, DV, C);
325 evalZeroParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000326}
327
Csaba Dabis0202c352019-08-22 00:20:36 +0000328//===----------------------------------------------------------------------===//
Csaba Dabis4d716002019-08-22 02:57:59 +0000329// Evaluating isa, isa_and_nonnull.
330//===----------------------------------------------------------------------===//
331
332void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
333 CheckerContext &C) const {
334 ProgramStateRef NonNullState, NullState;
335 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
336
337 if (NonNullState) {
338 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
339 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
340 }
341
342 if (NullState) {
343 C.generateSink(NullState, C.getPredecessor());
344 }
345}
346
347void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
348 DefinedOrUnknownSVal DV,
349 CheckerContext &C) const {
350 ProgramStateRef NonNullState, NullState;
351 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
352
353 if (NonNullState) {
354 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
355 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
356 }
357
358 if (NullState) {
359 addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
360 }
361}
362
363//===----------------------------------------------------------------------===//
Csaba Dabis0202c352019-08-22 00:20:36 +0000364// Main logic to evaluate a call.
365//===----------------------------------------------------------------------===//
366
Csaba Dabis693936a2019-07-10 00:20:03 +0000367bool CastValueChecker::evalCall(const CallEvent &Call,
368 CheckerContext &C) const {
Csaba Dabiscf229d52019-08-09 02:24:42 +0000369 const auto *Lookup = CDM.lookup(Call);
370 if (!Lookup)
Csaba Dabis693936a2019-07-10 00:20:03 +0000371 return false;
372
Csaba Dabiscf229d52019-08-09 02:24:42 +0000373 const CastCheck &Check = Lookup->first;
Csaba Dabis0202c352019-08-22 00:20:36 +0000374 CallKind Kind = Lookup->second;
Csaba Dabis4d716002019-08-22 02:57:59 +0000375
Csaba Dabiscf229d52019-08-09 02:24:42 +0000376 Optional<DefinedOrUnknownSVal> DV;
377
378 switch (Kind) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000379 case CallKind::Function: {
Artem Dergachevaf992e62019-08-23 03:23:58 +0000380 // We only model casts from pointers to pointers or from references
381 // to references. Other casts are most likely specialized and we
382 // cannot model them.
383 QualType ParamT = Call.parameters()[0]->getType();
384 QualType ResultT = Call.getResultType();
385 if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
386 !(ParamT->isReferenceType() && ResultT->isReferenceType()))
Csaba Dabiscf229d52019-08-09 02:24:42 +0000387 return false;
388
389 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
390 break;
391 }
Csaba Dabis4d716002019-08-22 02:57:59 +0000392 case CallKind::InstanceOf: {
393 // We need to obtain the only template argument to determinte the type.
394 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
395 if (!FD || !FD->getTemplateSpecializationArgs())
396 return false;
397
398 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
399 break;
400 }
Csaba Dabis0202c352019-08-22 00:20:36 +0000401 case CallKind::Method:
Csaba Dabiscf229d52019-08-09 02:24:42 +0000402 const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
403 if (!InstanceCall)
404 return false;
405
406 DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
407 break;
408 }
409
410 if (!DV)
Csaba Dabis693936a2019-07-10 00:20:03 +0000411 return false;
412
Csaba Dabis0202c352019-08-22 00:20:36 +0000413 Check(this, Call, *DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000414 return true;
415}
416
Csaba Dabis693936a2019-07-10 00:20:03 +0000417void ento::registerCastValueChecker(CheckerManager &Mgr) {
418 Mgr.registerChecker<CastValueChecker>();
419}
420
421bool ento::shouldRegisterCastValueChecker(const LangOptions &LO) {
422 return true;
423}