xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp (revision e2f1cbae45f81f3cd9a4d3c2bcf69a094eb060fa)
1693936abSCsaba Dabis //===- CastValueChecker - Model implementation of custom RTTIs --*- C++ -*-===//
2693936abSCsaba Dabis //
3693936abSCsaba Dabis // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4693936abSCsaba Dabis // See https://llvm.org/LICENSE.txt for license information.
5693936abSCsaba Dabis // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6693936abSCsaba Dabis //
7693936abSCsaba Dabis //===----------------------------------------------------------------------===//
8693936abSCsaba Dabis //
9693936abSCsaba Dabis //  This defines CastValueChecker which models casts of custom RTTIs.
10693936abSCsaba Dabis //
110202c359SCsaba Dabis // TODO list:
120202c359SCsaba Dabis // - It only allows one succesful cast between two types however in the wild
130202c359SCsaba Dabis //   the object could be casted to multiple types.
140202c359SCsaba Dabis // - It needs to check the most likely type information from the dynamic type
150202c359SCsaba Dabis //   map to increase precision of dynamic casting.
160202c359SCsaba Dabis //
17693936abSCsaba Dabis //===----------------------------------------------------------------------===//
18693936abSCsaba Dabis 
194d71600cSCsaba Dabis #include "clang/AST/DeclTemplate.h"
20693936abSCsaba Dabis #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
21693936abSCsaba Dabis #include "clang/StaticAnalyzer/Core/Checker.h"
22693936abSCsaba Dabis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
230b9d3a6eSBalazs Benics #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
24693936abSCsaba Dabis #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
25693936abSCsaba Dabis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
260202c359SCsaba Dabis #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
27a1580d7bSKazu Hirata #include <optional>
28cf229d57SCsaba Dabis #include <utility>
29693936abSCsaba Dabis 
30693936abSCsaba Dabis using namespace clang;
31693936abSCsaba Dabis using namespace ento;
32693936abSCsaba Dabis 
33693936abSCsaba Dabis namespace {
34239c53b7SValeriy Savchenko class CastValueChecker : public Checker<check::DeadSymbols, eval::Call> {
354d71600cSCsaba Dabis   enum class CallKind { Function, Method, InstanceOf };
36cf229d57SCsaba Dabis 
37693936abSCsaba Dabis   using CastCheck =
380202c359SCsaba Dabis       std::function<void(const CastValueChecker *, const CallEvent &Call,
39693936abSCsaba Dabis                          DefinedOrUnknownSVal, CheckerContext &)>;
40693936abSCsaba Dabis 
41693936abSCsaba Dabis public:
42cf229d57SCsaba Dabis   // We have five cases to evaluate a cast:
430202c359SCsaba Dabis   // 1) The parameter is non-null, the return value is non-null.
440202c359SCsaba Dabis   // 2) The parameter is non-null, the return value is null.
450202c359SCsaba Dabis   // 3) The parameter is null, the return value is null.
46693936abSCsaba Dabis   // cast: 1;  dyn_cast: 1, 2;  cast_or_null: 1, 3;  dyn_cast_or_null: 1, 2, 3.
47cf229d57SCsaba Dabis   //
480202c359SCsaba Dabis   // 4) castAs: Has no parameter, the return value is non-null.
490202c359SCsaba Dabis   // 5) getAs:  Has no parameter, the return value is null or non-null.
504d71600cSCsaba Dabis   //
514d71600cSCsaba Dabis   // We have two cases to check the parameter is an instance of the given type.
524d71600cSCsaba Dabis   // 1) isa:             The parameter is non-null, returns boolean.
534d71600cSCsaba Dabis   // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean.
54693936abSCsaba Dabis   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
55239c53b7SValeriy Savchenko   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
56693936abSCsaba Dabis 
57693936abSCsaba Dabis private:
58cf229d57SCsaba Dabis   // These are known in the LLVM project. The pairs are in the following form:
59*e2f1cbaeSNagyDonat   // {{match-mode, {namespace, call}, argument-count}, {callback, kind}}
600202c359SCsaba Dabis   const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = {
61*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"llvm", "cast"}, 1},
620202c359SCsaba Dabis        {&CastValueChecker::evalCast, CallKind::Function}},
63*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"llvm", "dyn_cast"}, 1},
640202c359SCsaba Dabis        {&CastValueChecker::evalDynCast, CallKind::Function}},
65*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"llvm", "cast_or_null"}, 1},
660202c359SCsaba Dabis        {&CastValueChecker::evalCastOrNull, CallKind::Function}},
67*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"llvm", "dyn_cast_or_null"}, 1},
680202c359SCsaba Dabis        {&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
69*e2f1cbaeSNagyDonat       {{CDM::CXXMethod, {"clang", "castAs"}, 0},
700202c359SCsaba Dabis        {&CastValueChecker::evalCastAs, CallKind::Method}},
71*e2f1cbaeSNagyDonat       {{CDM::CXXMethod, {"clang", "getAs"}, 0},
724d71600cSCsaba Dabis        {&CastValueChecker::evalGetAs, CallKind::Method}},
73*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"llvm", "isa"}, 1},
744d71600cSCsaba Dabis        {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
75*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"llvm", "isa_and_nonnull"}, 1},
764d71600cSCsaba Dabis        {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
77693936abSCsaba Dabis 
780202c359SCsaba Dabis   void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
79693936abSCsaba Dabis                 CheckerContext &C) const;
800202c359SCsaba Dabis   void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
81693936abSCsaba Dabis                    CheckerContext &C) const;
820202c359SCsaba Dabis   void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
83693936abSCsaba Dabis                       CheckerContext &C) const;
840202c359SCsaba Dabis   void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
85cf229d57SCsaba Dabis                          CheckerContext &C) const;
860202c359SCsaba Dabis   void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
87cf229d57SCsaba Dabis                   CheckerContext &C) const;
880202c359SCsaba Dabis   void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
89693936abSCsaba Dabis                  CheckerContext &C) const;
904d71600cSCsaba Dabis   void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
914d71600cSCsaba Dabis                CheckerContext &C) const;
924d71600cSCsaba Dabis   void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
934d71600cSCsaba Dabis                          CheckerContext &C) const;
94693936abSCsaba Dabis };
95693936abSCsaba Dabis } // namespace
96693936abSCsaba Dabis 
isInfeasibleCast(const DynamicCastInfo * CastInfo,bool CastSucceeds)970202c359SCsaba Dabis static bool isInfeasibleCast(const DynamicCastInfo *CastInfo,
980202c359SCsaba Dabis                              bool CastSucceeds) {
990202c359SCsaba Dabis   if (!CastInfo)
1000202c359SCsaba Dabis     return false;
1010202c359SCsaba Dabis 
1020202c359SCsaba Dabis   return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds();
1030202c359SCsaba Dabis }
1040202c359SCsaba Dabis 
getNoteTag(CheckerContext & C,const DynamicCastInfo * CastInfo,QualType CastToTy,const Expr * Object,bool CastSucceeds,bool IsKnownCast)1050202c359SCsaba Dabis static const NoteTag *getNoteTag(CheckerContext &C,
1060202c359SCsaba Dabis                                  const DynamicCastInfo *CastInfo,
1070202c359SCsaba Dabis                                  QualType CastToTy, const Expr *Object,
1080202c359SCsaba Dabis                                  bool CastSucceeds, bool IsKnownCast) {
1090202c359SCsaba Dabis   std::string CastToName =
1105a9e7789SAdam Balogh       CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString()
111c7fa4e8aSVince Bridgers                : CastToTy.getAsString();
1120202c359SCsaba Dabis   Object = Object->IgnoreParenImpCasts();
113693936abSCsaba Dabis 
114cf229d57SCsaba Dabis   return C.getNoteTag(
11522dc44ffSCsaba Dabis       [=]() -> std::string {
116693936abSCsaba Dabis         SmallString<128> Msg;
117693936abSCsaba Dabis         llvm::raw_svector_ostream Out(Msg);
118693936abSCsaba Dabis 
1190202c359SCsaba Dabis         if (!IsKnownCast)
1200202c359SCsaba Dabis           Out << "Assuming ";
121cf229d57SCsaba Dabis 
1220202c359SCsaba Dabis         if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
12319701458SBruno Ricci           Out << '\'' << DRE->getDecl()->getDeclName() << '\'';
1240202c359SCsaba Dabis         } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
1250202c359SCsaba Dabis           Out << (IsKnownCast ? "Field '" : "field '")
12619701458SBruno Ricci               << ME->getMemberDecl()->getDeclName() << '\'';
1270202c359SCsaba Dabis         } else {
1280202c359SCsaba Dabis           Out << (IsKnownCast ? "The object" : "the object");
1290202c359SCsaba Dabis         }
1300202c359SCsaba Dabis 
1310202c359SCsaba Dabis         Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName
1320202c359SCsaba Dabis             << '\'';
133cf229d57SCsaba Dabis 
134adcd0268SBenjamin Kramer         return std::string(Out.str());
135693936abSCsaba Dabis       },
136693936abSCsaba Dabis       /*IsPrunable=*/true);
137cf229d57SCsaba Dabis }
138693936abSCsaba Dabis 
getNoteTag(CheckerContext & C,SmallVector<QualType,4> CastToTyVec,const Expr * Object,bool IsKnownCast)1394448affeSAdam Balogh static const NoteTag *getNoteTag(CheckerContext &C,
1404448affeSAdam Balogh                                  SmallVector<QualType, 4> CastToTyVec,
1414448affeSAdam Balogh                                  const Expr *Object,
1424448affeSAdam Balogh                                  bool IsKnownCast) {
1434448affeSAdam Balogh   Object = Object->IgnoreParenImpCasts();
1444448affeSAdam Balogh 
1454448affeSAdam Balogh   return C.getNoteTag(
1464448affeSAdam Balogh       [=]() -> std::string {
1474448affeSAdam Balogh         SmallString<128> Msg;
1484448affeSAdam Balogh         llvm::raw_svector_ostream Out(Msg);
1494448affeSAdam Balogh 
1504448affeSAdam Balogh         if (!IsKnownCast)
1514448affeSAdam Balogh           Out << "Assuming ";
1524448affeSAdam Balogh 
1534448affeSAdam Balogh         if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
1544448affeSAdam Balogh           Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
1554448affeSAdam Balogh         } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
1564448affeSAdam Balogh           Out << (IsKnownCast ? "Field '" : "field '")
1574448affeSAdam Balogh               << ME->getMemberDecl()->getNameAsString() << '\'';
1584448affeSAdam Balogh         } else {
1594448affeSAdam Balogh           Out << (IsKnownCast ? "The object" : "the object");
1604448affeSAdam Balogh         }
1614448affeSAdam Balogh         Out << " is";
1624448affeSAdam Balogh 
1634448affeSAdam Balogh         bool First = true;
1644448affeSAdam Balogh         for (QualType CastToTy: CastToTyVec) {
1654448affeSAdam Balogh           std::string CastToName =
166c7fa4e8aSVince Bridgers               CastToTy->getAsCXXRecordDecl()
167c7fa4e8aSVince Bridgers                   ? CastToTy->getAsCXXRecordDecl()->getNameAsString()
168c7fa4e8aSVince Bridgers                   : CastToTy.getAsString();
1694448affeSAdam Balogh           Out << ' ' << ((CastToTyVec.size() == 1) ? "not" :
1704448affeSAdam Balogh                          (First ? "neither" : "nor")) << " a '" << CastToName
1714448affeSAdam Balogh               << '\'';
1724448affeSAdam Balogh           First = false;
1734448affeSAdam Balogh         }
1744448affeSAdam Balogh 
1754448affeSAdam Balogh         return std::string(Out.str());
1764448affeSAdam Balogh       },
1774448affeSAdam Balogh       /*IsPrunable=*/true);
1784448affeSAdam Balogh }
1794448affeSAdam Balogh 
1800202c359SCsaba Dabis //===----------------------------------------------------------------------===//
1810202c359SCsaba Dabis // Main logic to evaluate a cast.
1820202c359SCsaba Dabis //===----------------------------------------------------------------------===//
1830202c359SCsaba Dabis 
alignReferenceTypes(QualType toAlign,QualType alignTowards,ASTContext & ACtx)18485f7294eSArtem Dergachev static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards,
18585f7294eSArtem Dergachev                                     ASTContext &ACtx) {
18685f7294eSArtem Dergachev   if (alignTowards->isLValueReferenceType() &&
18785f7294eSArtem Dergachev       alignTowards.isConstQualified()) {
18885f7294eSArtem Dergachev     toAlign.addConst();
18985f7294eSArtem Dergachev     return ACtx.getLValueReferenceType(toAlign);
19085f7294eSArtem Dergachev   } else if (alignTowards->isLValueReferenceType())
19185f7294eSArtem Dergachev     return ACtx.getLValueReferenceType(toAlign);
19285f7294eSArtem Dergachev   else if (alignTowards->isRValueReferenceType())
19385f7294eSArtem Dergachev     return ACtx.getRValueReferenceType(toAlign);
19485f7294eSArtem Dergachev 
19585f7294eSArtem Dergachev   llvm_unreachable("Must align towards a reference type!");
19685f7294eSArtem Dergachev }
19785f7294eSArtem Dergachev 
addCastTransition(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C,bool IsNonNullParam,bool IsNonNullReturn,bool IsCheckedCast=false)1980202c359SCsaba Dabis static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
1990202c359SCsaba Dabis                               CheckerContext &C, bool IsNonNullParam,
2000202c359SCsaba Dabis                               bool IsNonNullReturn,
2010202c359SCsaba Dabis                               bool IsCheckedCast = false) {
2020202c359SCsaba Dabis   ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
2030202c359SCsaba Dabis   if (!State)
2040202c359SCsaba Dabis     return;
2050202c359SCsaba Dabis 
2060202c359SCsaba Dabis   const Expr *Object;
2070202c359SCsaba Dabis   QualType CastFromTy;
20862a76d0aSArtem Dergachev   QualType CastToTy = Call.getResultType();
2090202c359SCsaba Dabis 
2100202c359SCsaba Dabis   if (Call.getNumArgs() > 0) {
2110202c359SCsaba Dabis     Object = Call.getArgExpr(0);
21262a76d0aSArtem Dergachev     CastFromTy = Call.parameters()[0]->getType();
2130202c359SCsaba Dabis   } else {
2140202c359SCsaba Dabis     Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
21562a76d0aSArtem Dergachev     CastFromTy = Object->getType();
21685f7294eSArtem Dergachev     if (CastToTy->isPointerType()) {
21785f7294eSArtem Dergachev       if (!CastFromTy->isPointerType())
21885f7294eSArtem Dergachev         return;
21985f7294eSArtem Dergachev     } else {
22085f7294eSArtem Dergachev       if (!CastFromTy->isReferenceType())
22185f7294eSArtem Dergachev         return;
22285f7294eSArtem Dergachev 
22385f7294eSArtem Dergachev       CastFromTy = alignReferenceTypes(CastFromTy, CastToTy, C.getASTContext());
22485f7294eSArtem Dergachev     }
2250202c359SCsaba Dabis   }
2260202c359SCsaba Dabis 
2270202c359SCsaba Dabis   const MemRegion *MR = DV.getAsRegion();
2280202c359SCsaba Dabis   const DynamicCastInfo *CastInfo =
2290202c359SCsaba Dabis       getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
2300202c359SCsaba Dabis 
2310202c359SCsaba Dabis   // We assume that every checked cast succeeds.
2320202c359SCsaba Dabis   bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
2330202c359SCsaba Dabis   if (!CastSucceeds) {
2340202c359SCsaba Dabis     if (CastInfo)
2350202c359SCsaba Dabis       CastSucceeds = IsNonNullReturn && CastInfo->succeeds();
2360202c359SCsaba Dabis     else
2370202c359SCsaba Dabis       CastSucceeds = IsNonNullReturn;
2380202c359SCsaba Dabis   }
2390202c359SCsaba Dabis 
2400202c359SCsaba Dabis   // Check for infeasible casts.
2410202c359SCsaba Dabis   if (isInfeasibleCast(CastInfo, CastSucceeds)) {
2420202c359SCsaba Dabis     C.generateSink(State, C.getPredecessor());
2430202c359SCsaba Dabis     return;
2440202c359SCsaba Dabis   }
2450202c359SCsaba Dabis 
2460202c359SCsaba Dabis   // Store the type and the cast information.
2470202c359SCsaba Dabis   bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
2480202c359SCsaba Dabis   if (!IsKnownCast || IsCheckedCast)
2490202c359SCsaba Dabis     State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
25062a76d0aSArtem Dergachev                                       CastSucceeds);
2510202c359SCsaba Dabis 
25285f7294eSArtem Dergachev   SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
25398588841SVince Bridgers                         : C.getSValBuilder().makeNullWithType(CastToTy);
2540202c359SCsaba Dabis   C.addTransition(
2550202c359SCsaba Dabis       State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
2560202c359SCsaba Dabis       getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
257cf229d57SCsaba Dabis }
258cf229d57SCsaba Dabis 
addInstanceOfTransition(const CallEvent & Call,DefinedOrUnknownSVal DV,ProgramStateRef State,CheckerContext & C,bool IsInstanceOf)2594d71600cSCsaba Dabis static void addInstanceOfTransition(const CallEvent &Call,
2604d71600cSCsaba Dabis                                     DefinedOrUnknownSVal DV,
2614d71600cSCsaba Dabis                                     ProgramStateRef State, CheckerContext &C,
2624d71600cSCsaba Dabis                                     bool IsInstanceOf) {
2634d71600cSCsaba Dabis   const FunctionDecl *FD = Call.getDecl()->getAsFunction();
26462a76d0aSArtem Dergachev   QualType CastFromTy = Call.parameters()[0]->getType();
2654448affeSAdam Balogh   SmallVector<QualType, 4> CastToTyVec;
2664448affeSAdam Balogh   for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1;
2674448affeSAdam Balogh        ++idx) {
2684448affeSAdam Balogh     TemplateArgument CastToTempArg =
2694448affeSAdam Balogh       FD->getTemplateSpecializationArgs()->get(idx);
2704448affeSAdam Balogh     switch (CastToTempArg.getKind()) {
2714448affeSAdam Balogh     default:
2724448affeSAdam Balogh       return;
2734448affeSAdam Balogh     case TemplateArgument::Type:
2744448affeSAdam Balogh       CastToTyVec.push_back(CastToTempArg.getAsType());
2754448affeSAdam Balogh       break;
2764448affeSAdam Balogh     case TemplateArgument::Pack:
2774448affeSAdam Balogh       for (TemplateArgument ArgInPack: CastToTempArg.pack_elements())
2784448affeSAdam Balogh         CastToTyVec.push_back(ArgInPack.getAsType());
2794448affeSAdam Balogh       break;
2804448affeSAdam Balogh     }
2814448affeSAdam Balogh   }
2824448affeSAdam Balogh 
2834448affeSAdam Balogh   const MemRegion *MR = DV.getAsRegion();
2844448affeSAdam Balogh   if (MR && CastFromTy->isReferenceType())
2854448affeSAdam Balogh     MR = State->getSVal(DV.castAs<Loc>()).getAsRegion();
2864448affeSAdam Balogh 
2874448affeSAdam Balogh   bool Success = false;
2884448affeSAdam Balogh   bool IsAnyKnown = false;
2894448affeSAdam Balogh   for (QualType CastToTy: CastToTyVec) {
29062a76d0aSArtem Dergachev     if (CastFromTy->isPointerType())
29162a76d0aSArtem Dergachev       CastToTy = C.getASTContext().getPointerType(CastToTy);
29285f7294eSArtem Dergachev     else if (CastFromTy->isReferenceType())
29385f7294eSArtem Dergachev       CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
29462a76d0aSArtem Dergachev     else
29562a76d0aSArtem Dergachev       return;
2964d71600cSCsaba Dabis 
2974d71600cSCsaba Dabis     const DynamicCastInfo *CastInfo =
2984d71600cSCsaba Dabis       getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
2994d71600cSCsaba Dabis 
3004d71600cSCsaba Dabis     bool CastSucceeds;
3014d71600cSCsaba Dabis     if (CastInfo)
3024d71600cSCsaba Dabis       CastSucceeds = IsInstanceOf && CastInfo->succeeds();
3034d71600cSCsaba Dabis     else
3044d71600cSCsaba Dabis       CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
3054d71600cSCsaba Dabis 
3064d71600cSCsaba Dabis     // Store the type and the cast information.
3074d71600cSCsaba Dabis     bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
3084448affeSAdam Balogh     IsAnyKnown = IsAnyKnown || IsKnownCast;
3094448affeSAdam Balogh     ProgramStateRef NewState = State;
3104d71600cSCsaba Dabis     if (!IsKnownCast)
3114448affeSAdam Balogh       NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
31262a76d0aSArtem Dergachev                                            IsInstanceOf);
3134d71600cSCsaba Dabis 
3144448affeSAdam Balogh     if (CastSucceeds) {
3154448affeSAdam Balogh       Success = true;
3164448affeSAdam Balogh       C.addTransition(
3174448affeSAdam Balogh           NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
3184448affeSAdam Balogh                              C.getSValBuilder().makeTruthVal(true)),
3194448affeSAdam Balogh           getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true,
3204448affeSAdam Balogh                      IsKnownCast));
3214448affeSAdam Balogh       if (IsKnownCast)
3224448affeSAdam Balogh         return;
3234448affeSAdam Balogh     } else if (CastInfo && CastInfo->succeeds()) {
3244448affeSAdam Balogh       C.generateSink(NewState, C.getPredecessor());
3254448affeSAdam Balogh       return;
3264448affeSAdam Balogh     }
3274448affeSAdam Balogh   }
3284448affeSAdam Balogh 
3294448affeSAdam Balogh   if (!Success) {
3304d71600cSCsaba Dabis     C.addTransition(
3314d71600cSCsaba Dabis         State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
3324448affeSAdam Balogh                         C.getSValBuilder().makeTruthVal(false)),
3334448affeSAdam Balogh         getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown));
3344448affeSAdam Balogh   }
3354d71600cSCsaba Dabis }
3364d71600cSCsaba Dabis 
337cf229d57SCsaba Dabis //===----------------------------------------------------------------------===//
338cf229d57SCsaba Dabis // Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null.
339cf229d57SCsaba Dabis //===----------------------------------------------------------------------===//
340cf229d57SCsaba Dabis 
evalNonNullParamNonNullReturn(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C,bool IsCheckedCast=false)3410202c359SCsaba Dabis static void evalNonNullParamNonNullReturn(const CallEvent &Call,
342cf229d57SCsaba Dabis                                           DefinedOrUnknownSVal DV,
343cf229d57SCsaba Dabis                                           CheckerContext &C,
344cf229d57SCsaba Dabis                                           bool IsCheckedCast = false) {
3450202c359SCsaba Dabis   addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
3460202c359SCsaba Dabis                     /*IsNonNullReturn=*/true, IsCheckedCast);
347693936abSCsaba Dabis }
348693936abSCsaba Dabis 
evalNonNullParamNullReturn(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C)3490202c359SCsaba Dabis static void evalNonNullParamNullReturn(const CallEvent &Call,
350cf229d57SCsaba Dabis                                        DefinedOrUnknownSVal DV,
351693936abSCsaba Dabis                                        CheckerContext &C) {
3520202c359SCsaba Dabis   addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
3530202c359SCsaba Dabis                     /*IsNonNullReturn=*/false);
354693936abSCsaba Dabis }
355693936abSCsaba Dabis 
evalNullParamNullReturn(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C)3560202c359SCsaba Dabis static void evalNullParamNullReturn(const CallEvent &Call,
3570202c359SCsaba Dabis                                     DefinedOrUnknownSVal DV,
358693936abSCsaba Dabis                                     CheckerContext &C) {
359cf229d57SCsaba Dabis   if (ProgramStateRef State = C.getState()->assume(DV, false))
3600202c359SCsaba Dabis     C.addTransition(State->BindExpr(Call.getOriginExpr(),
3610202c359SCsaba Dabis                                     C.getLocationContext(),
36298588841SVince Bridgers                                     C.getSValBuilder().makeNullWithType(
36398588841SVince Bridgers                                         Call.getOriginExpr()->getType()),
36498588841SVince Bridgers                                     false),
365693936abSCsaba Dabis                     C.getNoteTag("Assuming null pointer is passed into cast",
366cf229d57SCsaba Dabis                                  /*IsPrunable=*/true));
367693936abSCsaba Dabis }
368693936abSCsaba Dabis 
evalCast(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C) const3690202c359SCsaba Dabis void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
370693936abSCsaba Dabis                                 CheckerContext &C) const {
3710202c359SCsaba Dabis   evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
372693936abSCsaba Dabis }
373693936abSCsaba Dabis 
evalDynCast(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C) const3740202c359SCsaba Dabis void CastValueChecker::evalDynCast(const CallEvent &Call,
375cf229d57SCsaba Dabis                                    DefinedOrUnknownSVal DV,
376693936abSCsaba Dabis                                    CheckerContext &C) const {
3770202c359SCsaba Dabis   evalNonNullParamNonNullReturn(Call, DV, C);
3780202c359SCsaba Dabis   evalNonNullParamNullReturn(Call, DV, C);
379693936abSCsaba Dabis }
380693936abSCsaba Dabis 
evalCastOrNull(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C) const3810202c359SCsaba Dabis void CastValueChecker::evalCastOrNull(const CallEvent &Call,
382cf229d57SCsaba Dabis                                       DefinedOrUnknownSVal DV,
383693936abSCsaba Dabis                                       CheckerContext &C) const {
3840202c359SCsaba Dabis   evalNonNullParamNonNullReturn(Call, DV, C);
3850202c359SCsaba Dabis   evalNullParamNullReturn(Call, DV, C);
3860202c359SCsaba Dabis }
3870202c359SCsaba Dabis 
evalDynCastOrNull(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C) const3880202c359SCsaba Dabis void CastValueChecker::evalDynCastOrNull(const CallEvent &Call,
3890202c359SCsaba Dabis                                          DefinedOrUnknownSVal DV,
3900202c359SCsaba Dabis                                          CheckerContext &C) const {
3910202c359SCsaba Dabis   evalNonNullParamNonNullReturn(Call, DV, C);
3920202c359SCsaba Dabis   evalNonNullParamNullReturn(Call, DV, C);
3930202c359SCsaba Dabis   evalNullParamNullReturn(Call, DV, C);
394cf229d57SCsaba Dabis }
395cf229d57SCsaba Dabis 
396cf229d57SCsaba Dabis //===----------------------------------------------------------------------===//
397cf229d57SCsaba Dabis // Evaluating castAs, getAs.
398cf229d57SCsaba Dabis //===----------------------------------------------------------------------===//
399cf229d57SCsaba Dabis 
evalZeroParamNonNullReturn(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C,bool IsCheckedCast=false)4000202c359SCsaba Dabis static void evalZeroParamNonNullReturn(const CallEvent &Call,
401cf229d57SCsaba Dabis                                        DefinedOrUnknownSVal DV,
402cf229d57SCsaba Dabis                                        CheckerContext &C,
403cf229d57SCsaba Dabis                                        bool IsCheckedCast = false) {
4040202c359SCsaba Dabis   addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
4050202c359SCsaba Dabis                     /*IsNonNullReturn=*/true, IsCheckedCast);
406cf229d57SCsaba Dabis }
407cf229d57SCsaba Dabis 
evalZeroParamNullReturn(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C)4080202c359SCsaba Dabis static void evalZeroParamNullReturn(const CallEvent &Call,
4090202c359SCsaba Dabis                                     DefinedOrUnknownSVal DV,
410cf229d57SCsaba Dabis                                     CheckerContext &C) {
4110202c359SCsaba Dabis   addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
4120202c359SCsaba Dabis                     /*IsNonNullReturn=*/false);
413cf229d57SCsaba Dabis }
414cf229d57SCsaba Dabis 
evalCastAs(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C) const4150202c359SCsaba Dabis void CastValueChecker::evalCastAs(const CallEvent &Call,
4160202c359SCsaba Dabis                                   DefinedOrUnknownSVal DV,
417cf229d57SCsaba Dabis                                   CheckerContext &C) const {
4180202c359SCsaba Dabis   evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
419cf229d57SCsaba Dabis }
420cf229d57SCsaba Dabis 
evalGetAs(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C) const4210202c359SCsaba Dabis void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
422cf229d57SCsaba Dabis                                  CheckerContext &C) const {
4230202c359SCsaba Dabis   evalZeroParamNonNullReturn(Call, DV, C);
4240202c359SCsaba Dabis   evalZeroParamNullReturn(Call, DV, C);
425693936abSCsaba Dabis }
426693936abSCsaba Dabis 
4270202c359SCsaba Dabis //===----------------------------------------------------------------------===//
4284d71600cSCsaba Dabis // Evaluating isa, isa_and_nonnull.
4294d71600cSCsaba Dabis //===----------------------------------------------------------------------===//
4304d71600cSCsaba Dabis 
evalIsa(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C) const4314d71600cSCsaba Dabis void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
4324d71600cSCsaba Dabis                                CheckerContext &C) const {
4334d71600cSCsaba Dabis   ProgramStateRef NonNullState, NullState;
4344d71600cSCsaba Dabis   std::tie(NonNullState, NullState) = C.getState()->assume(DV);
4354d71600cSCsaba Dabis 
4364d71600cSCsaba Dabis   if (NonNullState) {
4374d71600cSCsaba Dabis     addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
4384d71600cSCsaba Dabis     addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
4394d71600cSCsaba Dabis   }
4404d71600cSCsaba Dabis 
4414d71600cSCsaba Dabis   if (NullState) {
4424d71600cSCsaba Dabis     C.generateSink(NullState, C.getPredecessor());
4434d71600cSCsaba Dabis   }
4444d71600cSCsaba Dabis }
4454d71600cSCsaba Dabis 
evalIsaAndNonNull(const CallEvent & Call,DefinedOrUnknownSVal DV,CheckerContext & C) const4464d71600cSCsaba Dabis void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
4474d71600cSCsaba Dabis                                          DefinedOrUnknownSVal DV,
4484d71600cSCsaba Dabis                                          CheckerContext &C) const {
4494d71600cSCsaba Dabis   ProgramStateRef NonNullState, NullState;
4504d71600cSCsaba Dabis   std::tie(NonNullState, NullState) = C.getState()->assume(DV);
4514d71600cSCsaba Dabis 
4524d71600cSCsaba Dabis   if (NonNullState) {
4534d71600cSCsaba Dabis     addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
4544d71600cSCsaba Dabis     addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
4554d71600cSCsaba Dabis   }
4564d71600cSCsaba Dabis 
4574d71600cSCsaba Dabis   if (NullState) {
4584d71600cSCsaba Dabis     addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
4594d71600cSCsaba Dabis   }
4604d71600cSCsaba Dabis }
4614d71600cSCsaba Dabis 
4624d71600cSCsaba Dabis //===----------------------------------------------------------------------===//
4630202c359SCsaba Dabis // Main logic to evaluate a call.
4640202c359SCsaba Dabis //===----------------------------------------------------------------------===//
4650202c359SCsaba Dabis 
evalCall(const CallEvent & Call,CheckerContext & C) const466693936abSCsaba Dabis bool CastValueChecker::evalCall(const CallEvent &Call,
467693936abSCsaba Dabis                                 CheckerContext &C) const {
468cf229d57SCsaba Dabis   const auto *Lookup = CDM.lookup(Call);
469cf229d57SCsaba Dabis   if (!Lookup)
470693936abSCsaba Dabis     return false;
471693936abSCsaba Dabis 
472cf229d57SCsaba Dabis   const CastCheck &Check = Lookup->first;
4730202c359SCsaba Dabis   CallKind Kind = Lookup->second;
4744d71600cSCsaba Dabis 
4756ad0788cSKazu Hirata   std::optional<DefinedOrUnknownSVal> DV;
476cf229d57SCsaba Dabis 
477cf229d57SCsaba Dabis   switch (Kind) {
4780202c359SCsaba Dabis   case CallKind::Function: {
479af992e6dSArtem Dergachev     // We only model casts from pointers to pointers or from references
480af992e6dSArtem Dergachev     // to references. Other casts are most likely specialized and we
481af992e6dSArtem Dergachev     // cannot model them.
482af992e6dSArtem Dergachev     QualType ParamT = Call.parameters()[0]->getType();
483af992e6dSArtem Dergachev     QualType ResultT = Call.getResultType();
484af992e6dSArtem Dergachev     if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
4854448affeSAdam Balogh         !(ParamT->isReferenceType() && ResultT->isReferenceType())) {
486693936abSCsaba Dabis       return false;
4874448affeSAdam Balogh     }
488693936abSCsaba Dabis 
489cf229d57SCsaba Dabis     DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
490cf229d57SCsaba Dabis     break;
491cf229d57SCsaba Dabis   }
4924d71600cSCsaba Dabis   case CallKind::InstanceOf: {
4934d71600cSCsaba Dabis     // We need to obtain the only template argument to determinte the type.
4944d71600cSCsaba Dabis     const FunctionDecl *FD = Call.getDecl()->getAsFunction();
4954d71600cSCsaba Dabis     if (!FD || !FD->getTemplateSpecializationArgs())
4964d71600cSCsaba Dabis       return false;
4974d71600cSCsaba Dabis 
4984d71600cSCsaba Dabis     DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
4994d71600cSCsaba Dabis     break;
5004d71600cSCsaba Dabis   }
5010202c359SCsaba Dabis   case CallKind::Method:
502cf229d57SCsaba Dabis     const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
503cf229d57SCsaba Dabis     if (!InstanceCall)
504693936abSCsaba Dabis       return false;
505693936abSCsaba Dabis 
506cf229d57SCsaba Dabis     DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
507cf229d57SCsaba Dabis     break;
508cf229d57SCsaba Dabis   }
509cf229d57SCsaba Dabis 
510cf229d57SCsaba Dabis   if (!DV)
511693936abSCsaba Dabis     return false;
512693936abSCsaba Dabis 
5130202c359SCsaba Dabis   Check(this, Call, *DV, C);
514693936abSCsaba Dabis   return true;
515693936abSCsaba Dabis }
516693936abSCsaba Dabis 
checkDeadSymbols(SymbolReaper & SR,CheckerContext & C) const517239c53b7SValeriy Savchenko void CastValueChecker::checkDeadSymbols(SymbolReaper &SR,
518239c53b7SValeriy Savchenko                                         CheckerContext &C) const {
519239c53b7SValeriy Savchenko   C.addTransition(removeDeadCasts(C.getState(), SR));
520239c53b7SValeriy Savchenko }
521239c53b7SValeriy Savchenko 
registerCastValueChecker(CheckerManager & Mgr)522693936abSCsaba Dabis void ento::registerCastValueChecker(CheckerManager &Mgr) {
523693936abSCsaba Dabis   Mgr.registerChecker<CastValueChecker>();
524693936abSCsaba Dabis }
525693936abSCsaba Dabis 
shouldRegisterCastValueChecker(const CheckerManager & mgr)526bda3dd0dSKirstóf Umann bool ento::shouldRegisterCastValueChecker(const CheckerManager &mgr) {
527693936abSCsaba Dabis   return true;
528693936abSCsaba Dabis }
529