"Fossies" - the Fresh Open Source Software Archive

Member "cfe-9.0.0.src/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp" (10 Jul 2019, 6818 Bytes) of package /linux/misc/cfe-9.0.0.src.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 //===- CastValueChecker - Model implementation of custom RTTIs --*- C++ -*-===//
    2 //
    3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
    4 // See https://llvm.org/LICENSE.txt for license information.
    5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
    6 //
    7 //===----------------------------------------------------------------------===//
    8 //
    9 // This defines CastValueChecker which models casts of custom RTTIs.
   10 //
   11 //===----------------------------------------------------------------------===//
   12 
   13 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
   14 #include "clang/StaticAnalyzer/Core/Checker.h"
   15 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
   16 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
   17 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
   18 #include "llvm/ADT/Optional.h"
   19 
   20 using namespace clang;
   21 using namespace ento;
   22 
   23 namespace {
   24 class CastValueChecker : public Checker<eval::Call> {
   25   using CastCheck =
   26       std::function<void(const CastValueChecker *, const CallExpr *,
   27                          DefinedOrUnknownSVal, CheckerContext &)>;
   28 
   29 public:
   30   // We have three cases to evaluate a cast:
   31   // 1) The parameter is non-null, the return value is non-null
   32   // 2) The parameter is non-null, the return value is null
   33   // 3) The parameter is null, the return value is null
   34   //
   35   // cast: 1;  dyn_cast: 1, 2;  cast_or_null: 1, 3;  dyn_cast_or_null: 1, 2, 3.
   36   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
   37 
   38 private:
   39   // These are known in the LLVM project.
   40   const CallDescriptionMap<CastCheck> CDM = {
   41       {{{"llvm", "cast"}, 1}, &CastValueChecker::evalCast},
   42       {{{"llvm", "dyn_cast"}, 1}, &CastValueChecker::evalDynCast},
   43       {{{"llvm", "cast_or_null"}, 1}, &CastValueChecker::evalCastOrNull},
   44       {{{"llvm", "dyn_cast_or_null"}, 1},
   45        &CastValueChecker::evalDynCastOrNull}};
   46 
   47   void evalCast(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
   48                 CheckerContext &C) const;
   49   void evalDynCast(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
   50                    CheckerContext &C) const;
   51   void evalCastOrNull(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
   52                       CheckerContext &C) const;
   53   void evalDynCastOrNull(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
   54                          CheckerContext &C) const;
   55 };
   56 } // namespace
   57 
   58 static std::string getCastName(const Expr *Cast) {
   59   return Cast->getType()->getPointeeCXXRecordDecl()->getNameAsString();
   60 }
   61 
   62 static void evalNonNullParamNonNullReturn(const CallExpr *CE,
   63                                           DefinedOrUnknownSVal ParamDV,
   64                                           CheckerContext &C) {
   65   ProgramStateRef State = C.getState()->assume(ParamDV, true);
   66   if (!State)
   67     return;
   68 
   69   State = State->BindExpr(CE, C.getLocationContext(), ParamDV, false);
   70 
   71   std::string CastFromName = getCastName(CE->getArg(0));
   72   std::string CastToName = getCastName(CE);
   73 
   74   const NoteTag *CastTag = C.getNoteTag(
   75       [CastFromName, CastToName](BugReport &) -> std::string {
   76         SmallString<128> Msg;
   77         llvm::raw_svector_ostream Out(Msg);
   78 
   79         Out << "Assuming dynamic cast from '" << CastFromName << "' to '"
   80             << CastToName << "' succeeds";
   81         return Out.str();
   82       },
   83       /*IsPrunable=*/true);
   84 
   85   C.addTransition(State, CastTag);
   86 }
   87 
   88 static void evalNonNullParamNullReturn(const CallExpr *CE,
   89                                        DefinedOrUnknownSVal ParamDV,
   90                                        CheckerContext &C) {
   91   ProgramStateRef State = C.getState()->assume(ParamDV, true);
   92   if (!State)
   93     return;
   94 
   95   State = State->BindExpr(CE, C.getLocationContext(),
   96                           C.getSValBuilder().makeNull(), false);
   97 
   98   std::string CastFromName = getCastName(CE->getArg(0));
   99   std::string CastToName = getCastName(CE);
  100 
  101   const NoteTag *CastTag = C.getNoteTag(
  102       [CastFromName, CastToName](BugReport &) -> std::string {
  103         SmallString<128> Msg;
  104         llvm::raw_svector_ostream Out(Msg);
  105 
  106         Out << "Assuming dynamic cast from '" << CastFromName << "' to '"
  107             << CastToName << "' fails";
  108         return Out.str();
  109       },
  110       /*IsPrunable=*/true);
  111 
  112   C.addTransition(State, CastTag);
  113 }
  114 
  115 static void evalNullParamNullReturn(const CallExpr *CE,
  116                                     DefinedOrUnknownSVal ParamDV,
  117                                     CheckerContext &C) {
  118   ProgramStateRef State = C.getState()->assume(ParamDV, false);
  119   if (!State)
  120     return;
  121 
  122   State = State->BindExpr(CE, C.getLocationContext(),
  123                           C.getSValBuilder().makeNull(), false);
  124 
  125   const NoteTag *CastTag =
  126       C.getNoteTag("Assuming null pointer is passed into cast",
  127                    /*IsPrunable=*/true);
  128 
  129   C.addTransition(State, CastTag);
  130 }
  131 
  132 void CastValueChecker::evalCast(const CallExpr *CE,
  133                                 DefinedOrUnknownSVal ParamDV,
  134                                 CheckerContext &C) const {
  135   evalNonNullParamNonNullReturn(CE, ParamDV, C);
  136 }
  137 
  138 void CastValueChecker::evalDynCast(const CallExpr *CE,
  139                                    DefinedOrUnknownSVal ParamDV,
  140                                    CheckerContext &C) const {
  141   evalNonNullParamNonNullReturn(CE, ParamDV, C);
  142   evalNonNullParamNullReturn(CE, ParamDV, C);
  143 }
  144 
  145 void CastValueChecker::evalCastOrNull(const CallExpr *CE,
  146                                       DefinedOrUnknownSVal ParamDV,
  147                                       CheckerContext &C) const {
  148   evalNonNullParamNonNullReturn(CE, ParamDV, C);
  149   evalNullParamNullReturn(CE, ParamDV, C);
  150 }
  151 
  152 void CastValueChecker::evalDynCastOrNull(const CallExpr *CE,
  153                                          DefinedOrUnknownSVal ParamDV,
  154                                          CheckerContext &C) const {
  155   evalNonNullParamNonNullReturn(CE, ParamDV, C);
  156   evalNonNullParamNullReturn(CE, ParamDV, C);
  157   evalNullParamNullReturn(CE, ParamDV, C);
  158 }
  159 
  160 bool CastValueChecker::evalCall(const CallEvent &Call,
  161                                 CheckerContext &C) const {
  162   const CastCheck *Check = CDM.lookup(Call);
  163   if (!Check)
  164     return false;
  165 
  166   const auto *CE = cast<CallExpr>(Call.getOriginExpr());
  167   if (!CE)
  168     return false;
  169 
  170   // If we cannot obtain both of the classes we cannot be sure how to model it.
  171   if (!CE->getType()->getPointeeCXXRecordDecl() ||
  172       !CE->getArg(0)->getType()->getPointeeCXXRecordDecl())
  173     return false;
  174 
  175   SVal ParamV = Call.getArgSVal(0);
  176   auto ParamDV = ParamV.getAs<DefinedOrUnknownSVal>();
  177   if (!ParamDV)
  178     return false;
  179 
  180   (*Check)(this, CE, *ParamDV, C);
  181   return true;
  182 }
  183 
  184 void ento::registerCastValueChecker(CheckerManager &Mgr) {
  185   Mgr.registerChecker<CastValueChecker>();
  186 }
  187 
  188 bool ento::shouldRegisterCastValueChecker(const LangOptions &LO) {
  189   return true;
  190 }