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