xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp (revision ec727ea710c91afd8ce4f788c5aaa8482b7b69b2)
1e5dd7070Spatrick //===- CastValueChecker - Model implementation of custom RTTIs --*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick //  This defines CastValueChecker which models casts of custom RTTIs.
10e5dd7070Spatrick //
11e5dd7070Spatrick // TODO list:
12e5dd7070Spatrick // - It only allows one succesful cast between two types however in the wild
13e5dd7070Spatrick //   the object could be casted to multiple types.
14e5dd7070Spatrick // - It needs to check the most likely type information from the dynamic type
15e5dd7070Spatrick //   map to increase precision of dynamic casting.
16e5dd7070Spatrick //
17e5dd7070Spatrick //===----------------------------------------------------------------------===//
18e5dd7070Spatrick 
19e5dd7070Spatrick #include "clang/AST/DeclTemplate.h"
20e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
21e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
22e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h"
23e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
24e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
25e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
26e5dd7070Spatrick #include "llvm/ADT/Optional.h"
27e5dd7070Spatrick #include <utility>
28e5dd7070Spatrick 
29e5dd7070Spatrick using namespace clang;
30e5dd7070Spatrick using namespace ento;
31e5dd7070Spatrick 
32e5dd7070Spatrick namespace {
33*ec727ea7Spatrick class CastValueChecker : public Checker<check::DeadSymbols, eval::Call> {
34e5dd7070Spatrick   enum class CallKind { Function, Method, InstanceOf };
35e5dd7070Spatrick 
36e5dd7070Spatrick   using CastCheck =
37e5dd7070Spatrick       std::function<void(const CastValueChecker *, const CallEvent &Call,
38e5dd7070Spatrick                          DefinedOrUnknownSVal, CheckerContext &)>;
39e5dd7070Spatrick 
40e5dd7070Spatrick public:
41e5dd7070Spatrick   // We have five cases to evaluate a cast:
42e5dd7070Spatrick   // 1) The parameter is non-null, the return value is non-null.
43e5dd7070Spatrick   // 2) The parameter is non-null, the return value is null.
44e5dd7070Spatrick   // 3) The parameter is null, the return value is null.
45e5dd7070Spatrick   // cast: 1;  dyn_cast: 1, 2;  cast_or_null: 1, 3;  dyn_cast_or_null: 1, 2, 3.
46e5dd7070Spatrick   //
47e5dd7070Spatrick   // 4) castAs: Has no parameter, the return value is non-null.
48e5dd7070Spatrick   // 5) getAs:  Has no parameter, the return value is null or non-null.
49e5dd7070Spatrick   //
50e5dd7070Spatrick   // We have two cases to check the parameter is an instance of the given type.
51e5dd7070Spatrick   // 1) isa:             The parameter is non-null, returns boolean.
52e5dd7070Spatrick   // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean.
53e5dd7070Spatrick   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
54*ec727ea7Spatrick   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
55e5dd7070Spatrick 
56e5dd7070Spatrick private:
57e5dd7070Spatrick   // These are known in the LLVM project. The pairs are in the following form:
58e5dd7070Spatrick   // {{{namespace, call}, argument-count}, {callback, kind}}
59e5dd7070Spatrick   const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = {
60e5dd7070Spatrick       {{{"llvm", "cast"}, 1},
61e5dd7070Spatrick        {&CastValueChecker::evalCast, CallKind::Function}},
62e5dd7070Spatrick       {{{"llvm", "dyn_cast"}, 1},
63e5dd7070Spatrick        {&CastValueChecker::evalDynCast, CallKind::Function}},
64e5dd7070Spatrick       {{{"llvm", "cast_or_null"}, 1},
65e5dd7070Spatrick        {&CastValueChecker::evalCastOrNull, CallKind::Function}},
66e5dd7070Spatrick       {{{"llvm", "dyn_cast_or_null"}, 1},
67e5dd7070Spatrick        {&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
68e5dd7070Spatrick       {{{"clang", "castAs"}, 0},
69e5dd7070Spatrick        {&CastValueChecker::evalCastAs, CallKind::Method}},
70e5dd7070Spatrick       {{{"clang", "getAs"}, 0},
71e5dd7070Spatrick        {&CastValueChecker::evalGetAs, CallKind::Method}},
72e5dd7070Spatrick       {{{"llvm", "isa"}, 1},
73e5dd7070Spatrick        {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
74e5dd7070Spatrick       {{{"llvm", "isa_and_nonnull"}, 1},
75e5dd7070Spatrick        {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
76e5dd7070Spatrick 
77e5dd7070Spatrick   void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
78e5dd7070Spatrick                 CheckerContext &C) const;
79e5dd7070Spatrick   void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
80e5dd7070Spatrick                    CheckerContext &C) const;
81e5dd7070Spatrick   void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
82e5dd7070Spatrick                       CheckerContext &C) const;
83e5dd7070Spatrick   void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
84e5dd7070Spatrick                          CheckerContext &C) const;
85e5dd7070Spatrick   void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
86e5dd7070Spatrick                   CheckerContext &C) const;
87e5dd7070Spatrick   void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
88e5dd7070Spatrick                  CheckerContext &C) const;
89e5dd7070Spatrick   void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
90e5dd7070Spatrick                CheckerContext &C) const;
91e5dd7070Spatrick   void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
92e5dd7070Spatrick                          CheckerContext &C) const;
93e5dd7070Spatrick };
94e5dd7070Spatrick } // namespace
95e5dd7070Spatrick 
96e5dd7070Spatrick static bool isInfeasibleCast(const DynamicCastInfo *CastInfo,
97e5dd7070Spatrick                              bool CastSucceeds) {
98e5dd7070Spatrick   if (!CastInfo)
99e5dd7070Spatrick     return false;
100e5dd7070Spatrick 
101e5dd7070Spatrick   return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds();
102e5dd7070Spatrick }
103e5dd7070Spatrick 
104e5dd7070Spatrick static const NoteTag *getNoteTag(CheckerContext &C,
105e5dd7070Spatrick                                  const DynamicCastInfo *CastInfo,
106e5dd7070Spatrick                                  QualType CastToTy, const Expr *Object,
107e5dd7070Spatrick                                  bool CastSucceeds, bool IsKnownCast) {
108e5dd7070Spatrick   std::string CastToName =
109*ec727ea7Spatrick       CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString()
110e5dd7070Spatrick                : CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
111e5dd7070Spatrick   Object = Object->IgnoreParenImpCasts();
112e5dd7070Spatrick 
113e5dd7070Spatrick   return C.getNoteTag(
114e5dd7070Spatrick       [=]() -> std::string {
115e5dd7070Spatrick         SmallString<128> Msg;
116e5dd7070Spatrick         llvm::raw_svector_ostream Out(Msg);
117e5dd7070Spatrick 
118e5dd7070Spatrick         if (!IsKnownCast)
119e5dd7070Spatrick           Out << "Assuming ";
120e5dd7070Spatrick 
121e5dd7070Spatrick         if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
122e5dd7070Spatrick           Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
123e5dd7070Spatrick         } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
124e5dd7070Spatrick           Out << (IsKnownCast ? "Field '" : "field '")
125e5dd7070Spatrick               << ME->getMemberDecl()->getNameAsString() << '\'';
126e5dd7070Spatrick         } else {
127e5dd7070Spatrick           Out << (IsKnownCast ? "The object" : "the object");
128e5dd7070Spatrick         }
129e5dd7070Spatrick 
130e5dd7070Spatrick         Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName
131e5dd7070Spatrick             << '\'';
132e5dd7070Spatrick 
133*ec727ea7Spatrick         return std::string(Out.str());
134*ec727ea7Spatrick       },
135*ec727ea7Spatrick       /*IsPrunable=*/true);
136*ec727ea7Spatrick }
137*ec727ea7Spatrick 
138*ec727ea7Spatrick static const NoteTag *getNoteTag(CheckerContext &C,
139*ec727ea7Spatrick                                  SmallVector<QualType, 4> CastToTyVec,
140*ec727ea7Spatrick                                  const Expr *Object,
141*ec727ea7Spatrick                                  bool IsKnownCast) {
142*ec727ea7Spatrick   Object = Object->IgnoreParenImpCasts();
143*ec727ea7Spatrick 
144*ec727ea7Spatrick   return C.getNoteTag(
145*ec727ea7Spatrick       [=]() -> std::string {
146*ec727ea7Spatrick         SmallString<128> Msg;
147*ec727ea7Spatrick         llvm::raw_svector_ostream Out(Msg);
148*ec727ea7Spatrick 
149*ec727ea7Spatrick         if (!IsKnownCast)
150*ec727ea7Spatrick           Out << "Assuming ";
151*ec727ea7Spatrick 
152*ec727ea7Spatrick         if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
153*ec727ea7Spatrick           Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
154*ec727ea7Spatrick         } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
155*ec727ea7Spatrick           Out << (IsKnownCast ? "Field '" : "field '")
156*ec727ea7Spatrick               << ME->getMemberDecl()->getNameAsString() << '\'';
157*ec727ea7Spatrick         } else {
158*ec727ea7Spatrick           Out << (IsKnownCast ? "The object" : "the object");
159*ec727ea7Spatrick         }
160*ec727ea7Spatrick         Out << " is";
161*ec727ea7Spatrick 
162*ec727ea7Spatrick         bool First = true;
163*ec727ea7Spatrick         for (QualType CastToTy: CastToTyVec) {
164*ec727ea7Spatrick           std::string CastToName =
165*ec727ea7Spatrick             CastToTy->getAsCXXRecordDecl() ?
166*ec727ea7Spatrick             CastToTy->getAsCXXRecordDecl()->getNameAsString() :
167*ec727ea7Spatrick             CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
168*ec727ea7Spatrick           Out << ' ' << ((CastToTyVec.size() == 1) ? "not" :
169*ec727ea7Spatrick                          (First ? "neither" : "nor")) << " a '" << CastToName
170*ec727ea7Spatrick               << '\'';
171*ec727ea7Spatrick           First = false;
172*ec727ea7Spatrick         }
173*ec727ea7Spatrick 
174*ec727ea7Spatrick         return std::string(Out.str());
175e5dd7070Spatrick       },
176e5dd7070Spatrick       /*IsPrunable=*/true);
177e5dd7070Spatrick }
178e5dd7070Spatrick 
179e5dd7070Spatrick //===----------------------------------------------------------------------===//
180e5dd7070Spatrick // Main logic to evaluate a cast.
181e5dd7070Spatrick //===----------------------------------------------------------------------===//
182e5dd7070Spatrick 
183e5dd7070Spatrick static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards,
184e5dd7070Spatrick                                     ASTContext &ACtx) {
185e5dd7070Spatrick   if (alignTowards->isLValueReferenceType() &&
186e5dd7070Spatrick       alignTowards.isConstQualified()) {
187e5dd7070Spatrick     toAlign.addConst();
188e5dd7070Spatrick     return ACtx.getLValueReferenceType(toAlign);
189e5dd7070Spatrick   } else if (alignTowards->isLValueReferenceType())
190e5dd7070Spatrick     return ACtx.getLValueReferenceType(toAlign);
191e5dd7070Spatrick   else if (alignTowards->isRValueReferenceType())
192e5dd7070Spatrick     return ACtx.getRValueReferenceType(toAlign);
193e5dd7070Spatrick 
194e5dd7070Spatrick   llvm_unreachable("Must align towards a reference type!");
195e5dd7070Spatrick }
196e5dd7070Spatrick 
197e5dd7070Spatrick static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
198e5dd7070Spatrick                               CheckerContext &C, bool IsNonNullParam,
199e5dd7070Spatrick                               bool IsNonNullReturn,
200e5dd7070Spatrick                               bool IsCheckedCast = false) {
201e5dd7070Spatrick   ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
202e5dd7070Spatrick   if (!State)
203e5dd7070Spatrick     return;
204e5dd7070Spatrick 
205e5dd7070Spatrick   const Expr *Object;
206e5dd7070Spatrick   QualType CastFromTy;
207e5dd7070Spatrick   QualType CastToTy = Call.getResultType();
208e5dd7070Spatrick 
209e5dd7070Spatrick   if (Call.getNumArgs() > 0) {
210e5dd7070Spatrick     Object = Call.getArgExpr(0);
211e5dd7070Spatrick     CastFromTy = Call.parameters()[0]->getType();
212e5dd7070Spatrick   } else {
213e5dd7070Spatrick     Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
214e5dd7070Spatrick     CastFromTy = Object->getType();
215e5dd7070Spatrick     if (CastToTy->isPointerType()) {
216e5dd7070Spatrick       if (!CastFromTy->isPointerType())
217e5dd7070Spatrick         return;
218e5dd7070Spatrick     } else {
219e5dd7070Spatrick       if (!CastFromTy->isReferenceType())
220e5dd7070Spatrick         return;
221e5dd7070Spatrick 
222e5dd7070Spatrick       CastFromTy = alignReferenceTypes(CastFromTy, CastToTy, C.getASTContext());
223e5dd7070Spatrick     }
224e5dd7070Spatrick   }
225e5dd7070Spatrick 
226e5dd7070Spatrick   const MemRegion *MR = DV.getAsRegion();
227e5dd7070Spatrick   const DynamicCastInfo *CastInfo =
228e5dd7070Spatrick       getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
229e5dd7070Spatrick 
230e5dd7070Spatrick   // We assume that every checked cast succeeds.
231e5dd7070Spatrick   bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
232e5dd7070Spatrick   if (!CastSucceeds) {
233e5dd7070Spatrick     if (CastInfo)
234e5dd7070Spatrick       CastSucceeds = IsNonNullReturn && CastInfo->succeeds();
235e5dd7070Spatrick     else
236e5dd7070Spatrick       CastSucceeds = IsNonNullReturn;
237e5dd7070Spatrick   }
238e5dd7070Spatrick 
239e5dd7070Spatrick   // Check for infeasible casts.
240e5dd7070Spatrick   if (isInfeasibleCast(CastInfo, CastSucceeds)) {
241e5dd7070Spatrick     C.generateSink(State, C.getPredecessor());
242e5dd7070Spatrick     return;
243e5dd7070Spatrick   }
244e5dd7070Spatrick 
245e5dd7070Spatrick   // Store the type and the cast information.
246e5dd7070Spatrick   bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
247e5dd7070Spatrick   if (!IsKnownCast || IsCheckedCast)
248e5dd7070Spatrick     State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
249e5dd7070Spatrick                                       CastSucceeds);
250e5dd7070Spatrick 
251e5dd7070Spatrick   SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
252e5dd7070Spatrick                         : C.getSValBuilder().makeNull();
253e5dd7070Spatrick   C.addTransition(
254e5dd7070Spatrick       State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
255e5dd7070Spatrick       getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
256e5dd7070Spatrick }
257e5dd7070Spatrick 
258e5dd7070Spatrick static void addInstanceOfTransition(const CallEvent &Call,
259e5dd7070Spatrick                                     DefinedOrUnknownSVal DV,
260e5dd7070Spatrick                                     ProgramStateRef State, CheckerContext &C,
261e5dd7070Spatrick                                     bool IsInstanceOf) {
262e5dd7070Spatrick   const FunctionDecl *FD = Call.getDecl()->getAsFunction();
263e5dd7070Spatrick   QualType CastFromTy = Call.parameters()[0]->getType();
264*ec727ea7Spatrick   SmallVector<QualType, 4> CastToTyVec;
265*ec727ea7Spatrick   for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1;
266*ec727ea7Spatrick        ++idx) {
267*ec727ea7Spatrick     TemplateArgument CastToTempArg =
268*ec727ea7Spatrick       FD->getTemplateSpecializationArgs()->get(idx);
269*ec727ea7Spatrick     switch (CastToTempArg.getKind()) {
270*ec727ea7Spatrick     default:
271*ec727ea7Spatrick       return;
272*ec727ea7Spatrick     case TemplateArgument::Type:
273*ec727ea7Spatrick       CastToTyVec.push_back(CastToTempArg.getAsType());
274*ec727ea7Spatrick       break;
275*ec727ea7Spatrick     case TemplateArgument::Pack:
276*ec727ea7Spatrick       for (TemplateArgument ArgInPack: CastToTempArg.pack_elements())
277*ec727ea7Spatrick         CastToTyVec.push_back(ArgInPack.getAsType());
278*ec727ea7Spatrick       break;
279*ec727ea7Spatrick     }
280*ec727ea7Spatrick   }
281*ec727ea7Spatrick 
282*ec727ea7Spatrick   const MemRegion *MR = DV.getAsRegion();
283*ec727ea7Spatrick   if (MR && CastFromTy->isReferenceType())
284*ec727ea7Spatrick     MR = State->getSVal(DV.castAs<Loc>()).getAsRegion();
285*ec727ea7Spatrick 
286*ec727ea7Spatrick   bool Success = false;
287*ec727ea7Spatrick   bool IsAnyKnown = false;
288*ec727ea7Spatrick   for (QualType CastToTy: CastToTyVec) {
289e5dd7070Spatrick     if (CastFromTy->isPointerType())
290e5dd7070Spatrick       CastToTy = C.getASTContext().getPointerType(CastToTy);
291e5dd7070Spatrick     else if (CastFromTy->isReferenceType())
292e5dd7070Spatrick       CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
293e5dd7070Spatrick     else
294e5dd7070Spatrick       return;
295e5dd7070Spatrick 
296e5dd7070Spatrick     const DynamicCastInfo *CastInfo =
297e5dd7070Spatrick       getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
298e5dd7070Spatrick 
299e5dd7070Spatrick     bool CastSucceeds;
300e5dd7070Spatrick     if (CastInfo)
301e5dd7070Spatrick       CastSucceeds = IsInstanceOf && CastInfo->succeeds();
302e5dd7070Spatrick     else
303e5dd7070Spatrick       CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
304e5dd7070Spatrick 
305e5dd7070Spatrick     // Store the type and the cast information.
306e5dd7070Spatrick     bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
307*ec727ea7Spatrick     IsAnyKnown = IsAnyKnown || IsKnownCast;
308*ec727ea7Spatrick     ProgramStateRef NewState = State;
309e5dd7070Spatrick     if (!IsKnownCast)
310*ec727ea7Spatrick       NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
311e5dd7070Spatrick                                            IsInstanceOf);
312e5dd7070Spatrick 
313*ec727ea7Spatrick     if (CastSucceeds) {
314*ec727ea7Spatrick       Success = true;
315*ec727ea7Spatrick       C.addTransition(
316*ec727ea7Spatrick           NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
317*ec727ea7Spatrick                              C.getSValBuilder().makeTruthVal(true)),
318*ec727ea7Spatrick           getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true,
319*ec727ea7Spatrick                      IsKnownCast));
320*ec727ea7Spatrick       if (IsKnownCast)
321*ec727ea7Spatrick         return;
322*ec727ea7Spatrick     } else if (CastInfo && CastInfo->succeeds()) {
323*ec727ea7Spatrick       C.generateSink(NewState, C.getPredecessor());
324*ec727ea7Spatrick       return;
325*ec727ea7Spatrick     }
326*ec727ea7Spatrick   }
327*ec727ea7Spatrick 
328*ec727ea7Spatrick   if (!Success) {
329e5dd7070Spatrick     C.addTransition(
330e5dd7070Spatrick         State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
331*ec727ea7Spatrick                         C.getSValBuilder().makeTruthVal(false)),
332*ec727ea7Spatrick         getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown));
333*ec727ea7Spatrick   }
334e5dd7070Spatrick }
335e5dd7070Spatrick 
336e5dd7070Spatrick //===----------------------------------------------------------------------===//
337e5dd7070Spatrick // Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null.
338e5dd7070Spatrick //===----------------------------------------------------------------------===//
339e5dd7070Spatrick 
340e5dd7070Spatrick static void evalNonNullParamNonNullReturn(const CallEvent &Call,
341e5dd7070Spatrick                                           DefinedOrUnknownSVal DV,
342e5dd7070Spatrick                                           CheckerContext &C,
343e5dd7070Spatrick                                           bool IsCheckedCast = false) {
344e5dd7070Spatrick   addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
345e5dd7070Spatrick                     /*IsNonNullReturn=*/true, IsCheckedCast);
346e5dd7070Spatrick }
347e5dd7070Spatrick 
348e5dd7070Spatrick static void evalNonNullParamNullReturn(const CallEvent &Call,
349e5dd7070Spatrick                                        DefinedOrUnknownSVal DV,
350e5dd7070Spatrick                                        CheckerContext &C) {
351e5dd7070Spatrick   addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
352e5dd7070Spatrick                     /*IsNonNullReturn=*/false);
353e5dd7070Spatrick }
354e5dd7070Spatrick 
355e5dd7070Spatrick static void evalNullParamNullReturn(const CallEvent &Call,
356e5dd7070Spatrick                                     DefinedOrUnknownSVal DV,
357e5dd7070Spatrick                                     CheckerContext &C) {
358e5dd7070Spatrick   if (ProgramStateRef State = C.getState()->assume(DV, false))
359e5dd7070Spatrick     C.addTransition(State->BindExpr(Call.getOriginExpr(),
360e5dd7070Spatrick                                     C.getLocationContext(),
361e5dd7070Spatrick                                     C.getSValBuilder().makeNull(), false),
362e5dd7070Spatrick                     C.getNoteTag("Assuming null pointer is passed into cast",
363e5dd7070Spatrick                                  /*IsPrunable=*/true));
364e5dd7070Spatrick }
365e5dd7070Spatrick 
366e5dd7070Spatrick void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
367e5dd7070Spatrick                                 CheckerContext &C) const {
368e5dd7070Spatrick   evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
369e5dd7070Spatrick }
370e5dd7070Spatrick 
371e5dd7070Spatrick void CastValueChecker::evalDynCast(const CallEvent &Call,
372e5dd7070Spatrick                                    DefinedOrUnknownSVal DV,
373e5dd7070Spatrick                                    CheckerContext &C) const {
374e5dd7070Spatrick   evalNonNullParamNonNullReturn(Call, DV, C);
375e5dd7070Spatrick   evalNonNullParamNullReturn(Call, DV, C);
376e5dd7070Spatrick }
377e5dd7070Spatrick 
378e5dd7070Spatrick void CastValueChecker::evalCastOrNull(const CallEvent &Call,
379e5dd7070Spatrick                                       DefinedOrUnknownSVal DV,
380e5dd7070Spatrick                                       CheckerContext &C) const {
381e5dd7070Spatrick   evalNonNullParamNonNullReturn(Call, DV, C);
382e5dd7070Spatrick   evalNullParamNullReturn(Call, DV, C);
383e5dd7070Spatrick }
384e5dd7070Spatrick 
385e5dd7070Spatrick void CastValueChecker::evalDynCastOrNull(const CallEvent &Call,
386e5dd7070Spatrick                                          DefinedOrUnknownSVal DV,
387e5dd7070Spatrick                                          CheckerContext &C) const {
388e5dd7070Spatrick   evalNonNullParamNonNullReturn(Call, DV, C);
389e5dd7070Spatrick   evalNonNullParamNullReturn(Call, DV, C);
390e5dd7070Spatrick   evalNullParamNullReturn(Call, DV, C);
391e5dd7070Spatrick }
392e5dd7070Spatrick 
393e5dd7070Spatrick //===----------------------------------------------------------------------===//
394e5dd7070Spatrick // Evaluating castAs, getAs.
395e5dd7070Spatrick //===----------------------------------------------------------------------===//
396e5dd7070Spatrick 
397e5dd7070Spatrick static void evalZeroParamNonNullReturn(const CallEvent &Call,
398e5dd7070Spatrick                                        DefinedOrUnknownSVal DV,
399e5dd7070Spatrick                                        CheckerContext &C,
400e5dd7070Spatrick                                        bool IsCheckedCast = false) {
401e5dd7070Spatrick   addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
402e5dd7070Spatrick                     /*IsNonNullReturn=*/true, IsCheckedCast);
403e5dd7070Spatrick }
404e5dd7070Spatrick 
405e5dd7070Spatrick static void evalZeroParamNullReturn(const CallEvent &Call,
406e5dd7070Spatrick                                     DefinedOrUnknownSVal DV,
407e5dd7070Spatrick                                     CheckerContext &C) {
408e5dd7070Spatrick   addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
409e5dd7070Spatrick                     /*IsNonNullReturn=*/false);
410e5dd7070Spatrick }
411e5dd7070Spatrick 
412e5dd7070Spatrick void CastValueChecker::evalCastAs(const CallEvent &Call,
413e5dd7070Spatrick                                   DefinedOrUnknownSVal DV,
414e5dd7070Spatrick                                   CheckerContext &C) const {
415e5dd7070Spatrick   evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
416e5dd7070Spatrick }
417e5dd7070Spatrick 
418e5dd7070Spatrick void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
419e5dd7070Spatrick                                  CheckerContext &C) const {
420e5dd7070Spatrick   evalZeroParamNonNullReturn(Call, DV, C);
421e5dd7070Spatrick   evalZeroParamNullReturn(Call, DV, C);
422e5dd7070Spatrick }
423e5dd7070Spatrick 
424e5dd7070Spatrick //===----------------------------------------------------------------------===//
425e5dd7070Spatrick // Evaluating isa, isa_and_nonnull.
426e5dd7070Spatrick //===----------------------------------------------------------------------===//
427e5dd7070Spatrick 
428e5dd7070Spatrick void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
429e5dd7070Spatrick                                CheckerContext &C) const {
430e5dd7070Spatrick   ProgramStateRef NonNullState, NullState;
431e5dd7070Spatrick   std::tie(NonNullState, NullState) = C.getState()->assume(DV);
432e5dd7070Spatrick 
433e5dd7070Spatrick   if (NonNullState) {
434e5dd7070Spatrick     addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
435e5dd7070Spatrick     addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
436e5dd7070Spatrick   }
437e5dd7070Spatrick 
438e5dd7070Spatrick   if (NullState) {
439e5dd7070Spatrick     C.generateSink(NullState, C.getPredecessor());
440e5dd7070Spatrick   }
441e5dd7070Spatrick }
442e5dd7070Spatrick 
443e5dd7070Spatrick void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
444e5dd7070Spatrick                                          DefinedOrUnknownSVal DV,
445e5dd7070Spatrick                                          CheckerContext &C) const {
446e5dd7070Spatrick   ProgramStateRef NonNullState, NullState;
447e5dd7070Spatrick   std::tie(NonNullState, NullState) = C.getState()->assume(DV);
448e5dd7070Spatrick 
449e5dd7070Spatrick   if (NonNullState) {
450e5dd7070Spatrick     addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
451e5dd7070Spatrick     addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
452e5dd7070Spatrick   }
453e5dd7070Spatrick 
454e5dd7070Spatrick   if (NullState) {
455e5dd7070Spatrick     addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
456e5dd7070Spatrick   }
457e5dd7070Spatrick }
458e5dd7070Spatrick 
459e5dd7070Spatrick //===----------------------------------------------------------------------===//
460e5dd7070Spatrick // Main logic to evaluate a call.
461e5dd7070Spatrick //===----------------------------------------------------------------------===//
462e5dd7070Spatrick 
463e5dd7070Spatrick bool CastValueChecker::evalCall(const CallEvent &Call,
464e5dd7070Spatrick                                 CheckerContext &C) const {
465e5dd7070Spatrick   const auto *Lookup = CDM.lookup(Call);
466e5dd7070Spatrick   if (!Lookup)
467e5dd7070Spatrick     return false;
468e5dd7070Spatrick 
469e5dd7070Spatrick   const CastCheck &Check = Lookup->first;
470e5dd7070Spatrick   CallKind Kind = Lookup->second;
471e5dd7070Spatrick 
472e5dd7070Spatrick   Optional<DefinedOrUnknownSVal> DV;
473e5dd7070Spatrick 
474e5dd7070Spatrick   switch (Kind) {
475e5dd7070Spatrick   case CallKind::Function: {
476e5dd7070Spatrick     // We only model casts from pointers to pointers or from references
477e5dd7070Spatrick     // to references. Other casts are most likely specialized and we
478e5dd7070Spatrick     // cannot model them.
479e5dd7070Spatrick     QualType ParamT = Call.parameters()[0]->getType();
480e5dd7070Spatrick     QualType ResultT = Call.getResultType();
481e5dd7070Spatrick     if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
482*ec727ea7Spatrick         !(ParamT->isReferenceType() && ResultT->isReferenceType())) {
483e5dd7070Spatrick       return false;
484*ec727ea7Spatrick     }
485e5dd7070Spatrick 
486e5dd7070Spatrick     DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
487e5dd7070Spatrick     break;
488e5dd7070Spatrick   }
489e5dd7070Spatrick   case CallKind::InstanceOf: {
490e5dd7070Spatrick     // We need to obtain the only template argument to determinte the type.
491e5dd7070Spatrick     const FunctionDecl *FD = Call.getDecl()->getAsFunction();
492e5dd7070Spatrick     if (!FD || !FD->getTemplateSpecializationArgs())
493e5dd7070Spatrick       return false;
494e5dd7070Spatrick 
495e5dd7070Spatrick     DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
496e5dd7070Spatrick     break;
497e5dd7070Spatrick   }
498e5dd7070Spatrick   case CallKind::Method:
499e5dd7070Spatrick     const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
500e5dd7070Spatrick     if (!InstanceCall)
501e5dd7070Spatrick       return false;
502e5dd7070Spatrick 
503e5dd7070Spatrick     DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
504e5dd7070Spatrick     break;
505e5dd7070Spatrick   }
506e5dd7070Spatrick 
507e5dd7070Spatrick   if (!DV)
508e5dd7070Spatrick     return false;
509e5dd7070Spatrick 
510e5dd7070Spatrick   Check(this, Call, *DV, C);
511e5dd7070Spatrick   return true;
512e5dd7070Spatrick }
513e5dd7070Spatrick 
514*ec727ea7Spatrick void CastValueChecker::checkDeadSymbols(SymbolReaper &SR,
515*ec727ea7Spatrick                                         CheckerContext &C) const {
516*ec727ea7Spatrick   C.addTransition(removeDeadCasts(C.getState(), SR));
517*ec727ea7Spatrick }
518*ec727ea7Spatrick 
519e5dd7070Spatrick void ento::registerCastValueChecker(CheckerManager &Mgr) {
520e5dd7070Spatrick   Mgr.registerChecker<CastValueChecker>();
521e5dd7070Spatrick }
522e5dd7070Spatrick 
523*ec727ea7Spatrick bool ento::shouldRegisterCastValueChecker(const CheckerManager &mgr) {
524e5dd7070Spatrick   return true;
525e5dd7070Spatrick }
526