blob: cc1c9a66b90e26a00ccbdde6b10e5e20f7ba8e92 [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
Artem Dergachev85f72942019-08-23 03:24:04 +0000141static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards,
142 ASTContext &ACtx) {
143 if (alignTowards->isLValueReferenceType() &&
144 alignTowards.isConstQualified()) {
145 toAlign.addConst();
146 return ACtx.getLValueReferenceType(toAlign);
147 } else if (alignTowards->isLValueReferenceType())
148 return ACtx.getLValueReferenceType(toAlign);
149 else if (alignTowards->isRValueReferenceType())
150 return ACtx.getRValueReferenceType(toAlign);
151
152 llvm_unreachable("Must align towards a reference type!");
153}
154
Csaba Dabis0202c352019-08-22 00:20:36 +0000155static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
156 CheckerContext &C, bool IsNonNullParam,
157 bool IsNonNullReturn,
158 bool IsCheckedCast = false) {
159 ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
160 if (!State)
161 return;
162
163 const Expr *Object;
164 QualType CastFromTy;
Artem Dergachev62a76d02019-08-23 03:24:01 +0000165 QualType CastToTy = Call.getResultType();
Csaba Dabis0202c352019-08-22 00:20:36 +0000166
167 if (Call.getNumArgs() > 0) {
168 Object = Call.getArgExpr(0);
Artem Dergachev62a76d02019-08-23 03:24:01 +0000169 CastFromTy = Call.parameters()[0]->getType();
Csaba Dabis0202c352019-08-22 00:20:36 +0000170 } else {
171 Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
Artem Dergachev62a76d02019-08-23 03:24:01 +0000172 CastFromTy = Object->getType();
Artem Dergachev85f72942019-08-23 03:24:04 +0000173 if (CastToTy->isPointerType()) {
174 if (!CastFromTy->isPointerType())
175 return;
176 } else {
177 if (!CastFromTy->isReferenceType())
178 return;
179
180 CastFromTy = alignReferenceTypes(CastFromTy, CastToTy, C.getASTContext());
181 }
Csaba Dabis0202c352019-08-22 00:20:36 +0000182 }
183
184 const MemRegion *MR = DV.getAsRegion();
185 const DynamicCastInfo *CastInfo =
186 getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
187
188 // We assume that every checked cast succeeds.
189 bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
190 if (!CastSucceeds) {
191 if (CastInfo)
192 CastSucceeds = IsNonNullReturn && CastInfo->succeeds();
193 else
194 CastSucceeds = IsNonNullReturn;
195 }
196
197 // Check for infeasible casts.
198 if (isInfeasibleCast(CastInfo, CastSucceeds)) {
199 C.generateSink(State, C.getPredecessor());
200 return;
201 }
202
203 // Store the type and the cast information.
204 bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
205 if (!IsKnownCast || IsCheckedCast)
206 State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
Artem Dergachev62a76d02019-08-23 03:24:01 +0000207 CastSucceeds);
Csaba Dabis0202c352019-08-22 00:20:36 +0000208
Artem Dergachev85f72942019-08-23 03:24:04 +0000209 SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
210 : C.getSValBuilder().makeNull();
Csaba Dabis0202c352019-08-22 00:20:36 +0000211 C.addTransition(
212 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
213 getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
Csaba Dabiscf229d52019-08-09 02:24:42 +0000214}
215
Csaba Dabis4d716002019-08-22 02:57:59 +0000216static void addInstanceOfTransition(const CallEvent &Call,
217 DefinedOrUnknownSVal DV,
218 ProgramStateRef State, CheckerContext &C,
219 bool IsInstanceOf) {
220 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
Artem Dergachev62a76d02019-08-23 03:24:01 +0000221 QualType CastFromTy = Call.parameters()[0]->getType();
Csaba Dabis4d716002019-08-22 02:57:59 +0000222 QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType();
Artem Dergachev62a76d02019-08-23 03:24:01 +0000223 if (CastFromTy->isPointerType())
224 CastToTy = C.getASTContext().getPointerType(CastToTy);
Artem Dergachev85f72942019-08-23 03:24:04 +0000225 else if (CastFromTy->isReferenceType())
226 CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
Artem Dergachev62a76d02019-08-23 03:24:01 +0000227 else
228 return;
Csaba Dabis4d716002019-08-22 02:57:59 +0000229
230 const MemRegion *MR = DV.getAsRegion();
231 const DynamicCastInfo *CastInfo =
232 getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
233
234 bool CastSucceeds;
235 if (CastInfo)
236 CastSucceeds = IsInstanceOf && CastInfo->succeeds();
237 else
238 CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
239
240 if (isInfeasibleCast(CastInfo, CastSucceeds)) {
241 C.generateSink(State, C.getPredecessor());
242 return;
243 }
244
245 // Store the type and the cast information.
246 bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
247 if (!IsKnownCast)
248 State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
Artem Dergachev62a76d02019-08-23 03:24:01 +0000249 IsInstanceOf);
Csaba Dabis4d716002019-08-22 02:57:59 +0000250
251 C.addTransition(
252 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
253 C.getSValBuilder().makeTruthVal(CastSucceeds)),
254 getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
255 IsKnownCast));
256}
257
Csaba Dabiscf229d52019-08-09 02:24:42 +0000258//===----------------------------------------------------------------------===//
259// Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null.
260//===----------------------------------------------------------------------===//
261
Csaba Dabis0202c352019-08-22 00:20:36 +0000262static void evalNonNullParamNonNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000263 DefinedOrUnknownSVal DV,
264 CheckerContext &C,
265 bool IsCheckedCast = false) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000266 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
267 /*IsNonNullReturn=*/true, IsCheckedCast);
Csaba Dabis693936a2019-07-10 00:20:03 +0000268}
269
Csaba Dabis0202c352019-08-22 00:20:36 +0000270static void evalNonNullParamNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000271 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000272 CheckerContext &C) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000273 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
274 /*IsNonNullReturn=*/false);
Csaba Dabis693936a2019-07-10 00:20:03 +0000275}
276
Csaba Dabis0202c352019-08-22 00:20:36 +0000277static void evalNullParamNullReturn(const CallEvent &Call,
278 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000279 CheckerContext &C) {
Csaba Dabiscf229d52019-08-09 02:24:42 +0000280 if (ProgramStateRef State = C.getState()->assume(DV, false))
Csaba Dabis0202c352019-08-22 00:20:36 +0000281 C.addTransition(State->BindExpr(Call.getOriginExpr(),
282 C.getLocationContext(),
283 C.getSValBuilder().makeNull(), false),
Csaba Dabiscf229d52019-08-09 02:24:42 +0000284 C.getNoteTag("Assuming null pointer is passed into cast",
285 /*IsPrunable=*/true));
Csaba Dabis693936a2019-07-10 00:20:03 +0000286}
287
Csaba Dabis0202c352019-08-22 00:20:36 +0000288void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000289 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000290 evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
Csaba Dabis693936a2019-07-10 00:20:03 +0000291}
292
Csaba Dabis0202c352019-08-22 00:20:36 +0000293void CastValueChecker::evalDynCast(const CallEvent &Call,
294 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000295 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000296 evalNonNullParamNonNullReturn(Call, DV, C);
297 evalNonNullParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000298}
299
Csaba Dabis0202c352019-08-22 00:20:36 +0000300void CastValueChecker::evalCastOrNull(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000301 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000302 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000303 evalNonNullParamNonNullReturn(Call, DV, C);
304 evalNullParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000305}
306
Csaba Dabis0202c352019-08-22 00:20:36 +0000307void CastValueChecker::evalDynCastOrNull(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000308 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000309 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000310 evalNonNullParamNonNullReturn(Call, DV, C);
311 evalNonNullParamNullReturn(Call, DV, C);
312 evalNullParamNullReturn(Call, DV, C);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000313}
314
315//===----------------------------------------------------------------------===//
316// Evaluating castAs, getAs.
317//===----------------------------------------------------------------------===//
318
Csaba Dabis0202c352019-08-22 00:20:36 +0000319static void evalZeroParamNonNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000320 DefinedOrUnknownSVal DV,
321 CheckerContext &C,
322 bool IsCheckedCast = false) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000323 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
324 /*IsNonNullReturn=*/true, IsCheckedCast);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000325}
326
Csaba Dabis0202c352019-08-22 00:20:36 +0000327static void evalZeroParamNullReturn(const CallEvent &Call,
328 DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000329 CheckerContext &C) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000330 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
331 /*IsNonNullReturn=*/false);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000332}
333
Csaba Dabis0202c352019-08-22 00:20:36 +0000334void CastValueChecker::evalCastAs(const CallEvent &Call,
335 DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000336 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000337 evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000338}
339
Csaba Dabis0202c352019-08-22 00:20:36 +0000340void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000341 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000342 evalZeroParamNonNullReturn(Call, DV, C);
343 evalZeroParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000344}
345
Csaba Dabis0202c352019-08-22 00:20:36 +0000346//===----------------------------------------------------------------------===//
Csaba Dabis4d716002019-08-22 02:57:59 +0000347// Evaluating isa, isa_and_nonnull.
348//===----------------------------------------------------------------------===//
349
350void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
351 CheckerContext &C) const {
352 ProgramStateRef NonNullState, NullState;
353 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
354
355 if (NonNullState) {
356 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
357 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
358 }
359
360 if (NullState) {
361 C.generateSink(NullState, C.getPredecessor());
362 }
363}
364
365void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
366 DefinedOrUnknownSVal DV,
367 CheckerContext &C) const {
368 ProgramStateRef NonNullState, NullState;
369 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
370
371 if (NonNullState) {
372 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
373 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
374 }
375
376 if (NullState) {
377 addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
378 }
379}
380
381//===----------------------------------------------------------------------===//
Csaba Dabis0202c352019-08-22 00:20:36 +0000382// Main logic to evaluate a call.
383//===----------------------------------------------------------------------===//
384
Csaba Dabis693936a2019-07-10 00:20:03 +0000385bool CastValueChecker::evalCall(const CallEvent &Call,
386 CheckerContext &C) const {
Csaba Dabiscf229d52019-08-09 02:24:42 +0000387 const auto *Lookup = CDM.lookup(Call);
388 if (!Lookup)
Csaba Dabis693936a2019-07-10 00:20:03 +0000389 return false;
390
Csaba Dabiscf229d52019-08-09 02:24:42 +0000391 const CastCheck &Check = Lookup->first;
Csaba Dabis0202c352019-08-22 00:20:36 +0000392 CallKind Kind = Lookup->second;
Csaba Dabis4d716002019-08-22 02:57:59 +0000393
Csaba Dabiscf229d52019-08-09 02:24:42 +0000394 Optional<DefinedOrUnknownSVal> DV;
395
396 switch (Kind) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000397 case CallKind::Function: {
Artem Dergachevaf992e62019-08-23 03:23:58 +0000398 // We only model casts from pointers to pointers or from references
399 // to references. Other casts are most likely specialized and we
400 // cannot model them.
401 QualType ParamT = Call.parameters()[0]->getType();
402 QualType ResultT = Call.getResultType();
403 if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
404 !(ParamT->isReferenceType() && ResultT->isReferenceType()))
Csaba Dabiscf229d52019-08-09 02:24:42 +0000405 return false;
406
407 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
408 break;
409 }
Csaba Dabis4d716002019-08-22 02:57:59 +0000410 case CallKind::InstanceOf: {
411 // We need to obtain the only template argument to determinte the type.
412 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
413 if (!FD || !FD->getTemplateSpecializationArgs())
414 return false;
415
416 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
417 break;
418 }
Csaba Dabis0202c352019-08-22 00:20:36 +0000419 case CallKind::Method:
Csaba Dabiscf229d52019-08-09 02:24:42 +0000420 const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
421 if (!InstanceCall)
422 return false;
423
424 DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
425 break;
426 }
427
428 if (!DV)
Csaba Dabis693936a2019-07-10 00:20:03 +0000429 return false;
430
Csaba Dabis0202c352019-08-22 00:20:36 +0000431 Check(this, Call, *DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000432 return true;
433}
434
Csaba Dabis693936a2019-07-10 00:20:03 +0000435void ento::registerCastValueChecker(CheckerManager &Mgr) {
436 Mgr.registerChecker<CastValueChecker>();
437}
438
439bool ento::shouldRegisterCastValueChecker(const LangOptions &LO) {
440 return true;
441}