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" 23693936abSCsaba Dabis #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 24693936abSCsaba Dabis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 250202c359SCsaba Dabis #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" 26693936abSCsaba Dabis #include "llvm/ADT/Optional.h" 27cf229d57SCsaba Dabis #include <utility> 28693936abSCsaba Dabis 29693936abSCsaba Dabis using namespace clang; 30693936abSCsaba Dabis using namespace ento; 31693936abSCsaba Dabis 32693936abSCsaba Dabis namespace { 33693936abSCsaba Dabis class CastValueChecker : public Checker<eval::Call> { 344d71600cSCsaba Dabis enum class CallKind { Function, Method, InstanceOf }; 35cf229d57SCsaba Dabis 36693936abSCsaba Dabis using CastCheck = 370202c359SCsaba Dabis std::function<void(const CastValueChecker *, const CallEvent &Call, 38693936abSCsaba Dabis DefinedOrUnknownSVal, CheckerContext &)>; 39693936abSCsaba Dabis 40693936abSCsaba Dabis public: 41cf229d57SCsaba Dabis // We have five cases to evaluate a cast: 420202c359SCsaba Dabis // 1) The parameter is non-null, the return value is non-null. 430202c359SCsaba Dabis // 2) The parameter is non-null, the return value is null. 440202c359SCsaba Dabis // 3) The parameter is null, the return value is null. 45693936abSCsaba Dabis // cast: 1; dyn_cast: 1, 2; cast_or_null: 1, 3; dyn_cast_or_null: 1, 2, 3. 46cf229d57SCsaba Dabis // 470202c359SCsaba Dabis // 4) castAs: Has no parameter, the return value is non-null. 480202c359SCsaba Dabis // 5) getAs: Has no parameter, the return value is null or non-null. 494d71600cSCsaba Dabis // 504d71600cSCsaba Dabis // We have two cases to check the parameter is an instance of the given type. 514d71600cSCsaba Dabis // 1) isa: The parameter is non-null, returns boolean. 524d71600cSCsaba Dabis // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean. 53693936abSCsaba Dabis bool evalCall(const CallEvent &Call, CheckerContext &C) const; 54693936abSCsaba Dabis 55693936abSCsaba Dabis private: 56cf229d57SCsaba Dabis // These are known in the LLVM project. The pairs are in the following form: 57cf229d57SCsaba Dabis // {{{namespace, call}, argument-count}, {callback, kind}} 580202c359SCsaba Dabis const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = { 59cf229d57SCsaba Dabis {{{"llvm", "cast"}, 1}, 600202c359SCsaba Dabis {&CastValueChecker::evalCast, CallKind::Function}}, 61cf229d57SCsaba Dabis {{{"llvm", "dyn_cast"}, 1}, 620202c359SCsaba Dabis {&CastValueChecker::evalDynCast, CallKind::Function}}, 63cf229d57SCsaba Dabis {{{"llvm", "cast_or_null"}, 1}, 640202c359SCsaba Dabis {&CastValueChecker::evalCastOrNull, CallKind::Function}}, 65693936abSCsaba Dabis {{{"llvm", "dyn_cast_or_null"}, 1}, 660202c359SCsaba Dabis {&CastValueChecker::evalDynCastOrNull, CallKind::Function}}, 67cf229d57SCsaba Dabis {{{"clang", "castAs"}, 0}, 680202c359SCsaba Dabis {&CastValueChecker::evalCastAs, CallKind::Method}}, 69cf229d57SCsaba Dabis {{{"clang", "getAs"}, 0}, 704d71600cSCsaba Dabis {&CastValueChecker::evalGetAs, CallKind::Method}}, 714d71600cSCsaba Dabis {{{"llvm", "isa"}, 1}, 724d71600cSCsaba Dabis {&CastValueChecker::evalIsa, CallKind::InstanceOf}}, 734d71600cSCsaba Dabis {{{"llvm", "isa_and_nonnull"}, 1}, 744d71600cSCsaba Dabis {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}}; 75693936abSCsaba Dabis 760202c359SCsaba Dabis void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV, 77693936abSCsaba Dabis CheckerContext &C) const; 780202c359SCsaba Dabis void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV, 79693936abSCsaba Dabis CheckerContext &C) const; 800202c359SCsaba Dabis void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV, 81693936abSCsaba Dabis CheckerContext &C) const; 820202c359SCsaba Dabis void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV, 83cf229d57SCsaba Dabis CheckerContext &C) const; 840202c359SCsaba Dabis void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV, 85cf229d57SCsaba Dabis CheckerContext &C) const; 860202c359SCsaba Dabis void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV, 87693936abSCsaba Dabis CheckerContext &C) const; 884d71600cSCsaba Dabis void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV, 894d71600cSCsaba Dabis CheckerContext &C) const; 904d71600cSCsaba Dabis void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV, 914d71600cSCsaba Dabis CheckerContext &C) const; 92693936abSCsaba Dabis }; 93693936abSCsaba Dabis } // namespace 94693936abSCsaba Dabis 950202c359SCsaba Dabis static bool isInfeasibleCast(const DynamicCastInfo *CastInfo, 960202c359SCsaba Dabis bool CastSucceeds) { 970202c359SCsaba Dabis if (!CastInfo) 980202c359SCsaba Dabis return false; 990202c359SCsaba Dabis 1000202c359SCsaba Dabis return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds(); 1010202c359SCsaba Dabis } 1020202c359SCsaba Dabis 1030202c359SCsaba Dabis static const NoteTag *getNoteTag(CheckerContext &C, 1040202c359SCsaba Dabis const DynamicCastInfo *CastInfo, 1050202c359SCsaba Dabis QualType CastToTy, const Expr *Object, 1060202c359SCsaba Dabis bool CastSucceeds, bool IsKnownCast) { 1070202c359SCsaba Dabis std::string CastToName = 10862a76d0aSArtem Dergachev CastInfo ? CastInfo->to()->getPointeeCXXRecordDecl()->getNameAsString() 10962a76d0aSArtem Dergachev : CastToTy->getPointeeCXXRecordDecl()->getNameAsString(); 1100202c359SCsaba Dabis Object = Object->IgnoreParenImpCasts(); 111693936abSCsaba Dabis 112cf229d57SCsaba Dabis return C.getNoteTag( 11322dc44ffSCsaba Dabis [=]() -> std::string { 114693936abSCsaba Dabis SmallString<128> Msg; 115693936abSCsaba Dabis llvm::raw_svector_ostream Out(Msg); 116693936abSCsaba Dabis 1170202c359SCsaba Dabis if (!IsKnownCast) 1180202c359SCsaba Dabis Out << "Assuming "; 119cf229d57SCsaba Dabis 1200202c359SCsaba Dabis if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) { 1210202c359SCsaba Dabis Out << '\'' << DRE->getDecl()->getNameAsString() << '\''; 1220202c359SCsaba Dabis } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) { 1230202c359SCsaba Dabis Out << (IsKnownCast ? "Field '" : "field '") 1240202c359SCsaba Dabis << ME->getMemberDecl()->getNameAsString() << '\''; 1250202c359SCsaba Dabis } else { 1260202c359SCsaba Dabis Out << (IsKnownCast ? "The object" : "the object"); 1270202c359SCsaba Dabis } 1280202c359SCsaba Dabis 1290202c359SCsaba Dabis Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName 1300202c359SCsaba Dabis << '\''; 131cf229d57SCsaba Dabis 132693936abSCsaba Dabis return Out.str(); 133693936abSCsaba Dabis }, 134693936abSCsaba Dabis /*IsPrunable=*/true); 135cf229d57SCsaba Dabis } 136693936abSCsaba Dabis 1370202c359SCsaba Dabis //===----------------------------------------------------------------------===// 1380202c359SCsaba Dabis // Main logic to evaluate a cast. 1390202c359SCsaba Dabis //===----------------------------------------------------------------------===// 1400202c359SCsaba Dabis 141*85f7294eSArtem Dergachev static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards, 142*85f7294eSArtem Dergachev ASTContext &ACtx) { 143*85f7294eSArtem Dergachev if (alignTowards->isLValueReferenceType() && 144*85f7294eSArtem Dergachev alignTowards.isConstQualified()) { 145*85f7294eSArtem Dergachev toAlign.addConst(); 146*85f7294eSArtem Dergachev return ACtx.getLValueReferenceType(toAlign); 147*85f7294eSArtem Dergachev } else if (alignTowards->isLValueReferenceType()) 148*85f7294eSArtem Dergachev return ACtx.getLValueReferenceType(toAlign); 149*85f7294eSArtem Dergachev else if (alignTowards->isRValueReferenceType()) 150*85f7294eSArtem Dergachev return ACtx.getRValueReferenceType(toAlign); 151*85f7294eSArtem Dergachev 152*85f7294eSArtem Dergachev llvm_unreachable("Must align towards a reference type!"); 153*85f7294eSArtem Dergachev } 154*85f7294eSArtem Dergachev 1550202c359SCsaba Dabis static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV, 1560202c359SCsaba Dabis CheckerContext &C, bool IsNonNullParam, 1570202c359SCsaba Dabis bool IsNonNullReturn, 1580202c359SCsaba Dabis bool IsCheckedCast = false) { 1590202c359SCsaba Dabis ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam); 1600202c359SCsaba Dabis if (!State) 1610202c359SCsaba Dabis return; 1620202c359SCsaba Dabis 1630202c359SCsaba Dabis const Expr *Object; 1640202c359SCsaba Dabis QualType CastFromTy; 16562a76d0aSArtem Dergachev QualType CastToTy = Call.getResultType(); 1660202c359SCsaba Dabis 1670202c359SCsaba Dabis if (Call.getNumArgs() > 0) { 1680202c359SCsaba Dabis Object = Call.getArgExpr(0); 16962a76d0aSArtem Dergachev CastFromTy = Call.parameters()[0]->getType(); 1700202c359SCsaba Dabis } else { 1710202c359SCsaba Dabis Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr(); 17262a76d0aSArtem Dergachev CastFromTy = Object->getType(); 173*85f7294eSArtem Dergachev if (CastToTy->isPointerType()) { 174*85f7294eSArtem Dergachev if (!CastFromTy->isPointerType()) 175*85f7294eSArtem Dergachev return; 176*85f7294eSArtem Dergachev } else { 177*85f7294eSArtem Dergachev if (!CastFromTy->isReferenceType()) 178*85f7294eSArtem Dergachev return; 179*85f7294eSArtem Dergachev 180*85f7294eSArtem Dergachev CastFromTy = alignReferenceTypes(CastFromTy, CastToTy, C.getASTContext()); 181*85f7294eSArtem Dergachev } 1820202c359SCsaba Dabis } 1830202c359SCsaba Dabis 1840202c359SCsaba Dabis const MemRegion *MR = DV.getAsRegion(); 1850202c359SCsaba Dabis const DynamicCastInfo *CastInfo = 1860202c359SCsaba Dabis getDynamicCastInfo(State, MR, CastFromTy, CastToTy); 1870202c359SCsaba Dabis 1880202c359SCsaba Dabis // We assume that every checked cast succeeds. 1890202c359SCsaba Dabis bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy; 1900202c359SCsaba Dabis if (!CastSucceeds) { 1910202c359SCsaba Dabis if (CastInfo) 1920202c359SCsaba Dabis CastSucceeds = IsNonNullReturn && CastInfo->succeeds(); 1930202c359SCsaba Dabis else 1940202c359SCsaba Dabis CastSucceeds = IsNonNullReturn; 1950202c359SCsaba Dabis } 1960202c359SCsaba Dabis 1970202c359SCsaba Dabis // Check for infeasible casts. 1980202c359SCsaba Dabis if (isInfeasibleCast(CastInfo, CastSucceeds)) { 1990202c359SCsaba Dabis C.generateSink(State, C.getPredecessor()); 2000202c359SCsaba Dabis return; 2010202c359SCsaba Dabis } 2020202c359SCsaba Dabis 2030202c359SCsaba Dabis // Store the type and the cast information. 2040202c359SCsaba Dabis bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy; 2050202c359SCsaba Dabis if (!IsKnownCast || IsCheckedCast) 2060202c359SCsaba Dabis State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy, 20762a76d0aSArtem Dergachev CastSucceeds); 2080202c359SCsaba Dabis 209*85f7294eSArtem Dergachev SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy) 210*85f7294eSArtem Dergachev : C.getSValBuilder().makeNull(); 2110202c359SCsaba Dabis C.addTransition( 2120202c359SCsaba Dabis State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false), 2130202c359SCsaba Dabis getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast)); 214cf229d57SCsaba Dabis } 215cf229d57SCsaba Dabis 2164d71600cSCsaba Dabis static void addInstanceOfTransition(const CallEvent &Call, 2174d71600cSCsaba Dabis DefinedOrUnknownSVal DV, 2184d71600cSCsaba Dabis ProgramStateRef State, CheckerContext &C, 2194d71600cSCsaba Dabis bool IsInstanceOf) { 2204d71600cSCsaba Dabis const FunctionDecl *FD = Call.getDecl()->getAsFunction(); 22162a76d0aSArtem Dergachev QualType CastFromTy = Call.parameters()[0]->getType(); 2224d71600cSCsaba Dabis QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType(); 22362a76d0aSArtem Dergachev if (CastFromTy->isPointerType()) 22462a76d0aSArtem Dergachev CastToTy = C.getASTContext().getPointerType(CastToTy); 225*85f7294eSArtem Dergachev else if (CastFromTy->isReferenceType()) 226*85f7294eSArtem Dergachev CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext()); 22762a76d0aSArtem Dergachev else 22862a76d0aSArtem Dergachev return; 2294d71600cSCsaba Dabis 2304d71600cSCsaba Dabis const MemRegion *MR = DV.getAsRegion(); 2314d71600cSCsaba Dabis const DynamicCastInfo *CastInfo = 2324d71600cSCsaba Dabis getDynamicCastInfo(State, MR, CastFromTy, CastToTy); 2334d71600cSCsaba Dabis 2344d71600cSCsaba Dabis bool CastSucceeds; 2354d71600cSCsaba Dabis if (CastInfo) 2364d71600cSCsaba Dabis CastSucceeds = IsInstanceOf && CastInfo->succeeds(); 2374d71600cSCsaba Dabis else 2384d71600cSCsaba Dabis CastSucceeds = IsInstanceOf || CastFromTy == CastToTy; 2394d71600cSCsaba Dabis 2404d71600cSCsaba Dabis if (isInfeasibleCast(CastInfo, CastSucceeds)) { 2414d71600cSCsaba Dabis C.generateSink(State, C.getPredecessor()); 2424d71600cSCsaba Dabis return; 2434d71600cSCsaba Dabis } 2444d71600cSCsaba Dabis 2454d71600cSCsaba Dabis // Store the type and the cast information. 2464d71600cSCsaba Dabis bool IsKnownCast = CastInfo || CastFromTy == CastToTy; 2474d71600cSCsaba Dabis if (!IsKnownCast) 2484d71600cSCsaba Dabis State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy, 24962a76d0aSArtem Dergachev IsInstanceOf); 2504d71600cSCsaba Dabis 2514d71600cSCsaba Dabis C.addTransition( 2524d71600cSCsaba Dabis State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 2534d71600cSCsaba Dabis C.getSValBuilder().makeTruthVal(CastSucceeds)), 2544d71600cSCsaba Dabis getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds, 2554d71600cSCsaba Dabis IsKnownCast)); 2564d71600cSCsaba Dabis } 2574d71600cSCsaba Dabis 258cf229d57SCsaba Dabis //===----------------------------------------------------------------------===// 259cf229d57SCsaba Dabis // Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null. 260cf229d57SCsaba Dabis //===----------------------------------------------------------------------===// 261cf229d57SCsaba Dabis 2620202c359SCsaba Dabis static void evalNonNullParamNonNullReturn(const CallEvent &Call, 263cf229d57SCsaba Dabis DefinedOrUnknownSVal DV, 264cf229d57SCsaba Dabis CheckerContext &C, 265cf229d57SCsaba Dabis bool IsCheckedCast = false) { 2660202c359SCsaba Dabis addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 2670202c359SCsaba Dabis /*IsNonNullReturn=*/true, IsCheckedCast); 268693936abSCsaba Dabis } 269693936abSCsaba Dabis 2700202c359SCsaba Dabis static void evalNonNullParamNullReturn(const CallEvent &Call, 271cf229d57SCsaba Dabis DefinedOrUnknownSVal DV, 272693936abSCsaba Dabis CheckerContext &C) { 2730202c359SCsaba Dabis addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 2740202c359SCsaba Dabis /*IsNonNullReturn=*/false); 275693936abSCsaba Dabis } 276693936abSCsaba Dabis 2770202c359SCsaba Dabis static void evalNullParamNullReturn(const CallEvent &Call, 2780202c359SCsaba Dabis DefinedOrUnknownSVal DV, 279693936abSCsaba Dabis CheckerContext &C) { 280cf229d57SCsaba Dabis if (ProgramStateRef State = C.getState()->assume(DV, false)) 2810202c359SCsaba Dabis C.addTransition(State->BindExpr(Call.getOriginExpr(), 2820202c359SCsaba Dabis C.getLocationContext(), 2830202c359SCsaba Dabis C.getSValBuilder().makeNull(), false), 284693936abSCsaba Dabis C.getNoteTag("Assuming null pointer is passed into cast", 285cf229d57SCsaba Dabis /*IsPrunable=*/true)); 286693936abSCsaba Dabis } 287693936abSCsaba Dabis 2880202c359SCsaba Dabis void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV, 289693936abSCsaba Dabis CheckerContext &C) const { 2900202c359SCsaba Dabis evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true); 291693936abSCsaba Dabis } 292693936abSCsaba Dabis 2930202c359SCsaba Dabis void CastValueChecker::evalDynCast(const CallEvent &Call, 294cf229d57SCsaba Dabis DefinedOrUnknownSVal DV, 295693936abSCsaba Dabis CheckerContext &C) const { 2960202c359SCsaba Dabis evalNonNullParamNonNullReturn(Call, DV, C); 2970202c359SCsaba Dabis evalNonNullParamNullReturn(Call, DV, C); 298693936abSCsaba Dabis } 299693936abSCsaba Dabis 3000202c359SCsaba Dabis void CastValueChecker::evalCastOrNull(const CallEvent &Call, 301cf229d57SCsaba Dabis DefinedOrUnknownSVal DV, 302693936abSCsaba Dabis CheckerContext &C) const { 3030202c359SCsaba Dabis evalNonNullParamNonNullReturn(Call, DV, C); 3040202c359SCsaba Dabis evalNullParamNullReturn(Call, DV, C); 3050202c359SCsaba Dabis } 3060202c359SCsaba Dabis 3070202c359SCsaba Dabis void CastValueChecker::evalDynCastOrNull(const CallEvent &Call, 3080202c359SCsaba Dabis DefinedOrUnknownSVal DV, 3090202c359SCsaba Dabis CheckerContext &C) const { 3100202c359SCsaba Dabis evalNonNullParamNonNullReturn(Call, DV, C); 3110202c359SCsaba Dabis evalNonNullParamNullReturn(Call, DV, C); 3120202c359SCsaba Dabis evalNullParamNullReturn(Call, DV, C); 313cf229d57SCsaba Dabis } 314cf229d57SCsaba Dabis 315cf229d57SCsaba Dabis //===----------------------------------------------------------------------===// 316cf229d57SCsaba Dabis // Evaluating castAs, getAs. 317cf229d57SCsaba Dabis //===----------------------------------------------------------------------===// 318cf229d57SCsaba Dabis 3190202c359SCsaba Dabis static void evalZeroParamNonNullReturn(const CallEvent &Call, 320cf229d57SCsaba Dabis DefinedOrUnknownSVal DV, 321cf229d57SCsaba Dabis CheckerContext &C, 322cf229d57SCsaba Dabis bool IsCheckedCast = false) { 3230202c359SCsaba Dabis addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 3240202c359SCsaba Dabis /*IsNonNullReturn=*/true, IsCheckedCast); 325cf229d57SCsaba Dabis } 326cf229d57SCsaba Dabis 3270202c359SCsaba Dabis static void evalZeroParamNullReturn(const CallEvent &Call, 3280202c359SCsaba Dabis DefinedOrUnknownSVal DV, 329cf229d57SCsaba Dabis CheckerContext &C) { 3300202c359SCsaba Dabis addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 3310202c359SCsaba Dabis /*IsNonNullReturn=*/false); 332cf229d57SCsaba Dabis } 333cf229d57SCsaba Dabis 3340202c359SCsaba Dabis void CastValueChecker::evalCastAs(const CallEvent &Call, 3350202c359SCsaba Dabis DefinedOrUnknownSVal DV, 336cf229d57SCsaba Dabis CheckerContext &C) const { 3370202c359SCsaba Dabis evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true); 338cf229d57SCsaba Dabis } 339cf229d57SCsaba Dabis 3400202c359SCsaba Dabis void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV, 341cf229d57SCsaba Dabis CheckerContext &C) const { 3420202c359SCsaba Dabis evalZeroParamNonNullReturn(Call, DV, C); 3430202c359SCsaba Dabis evalZeroParamNullReturn(Call, DV, C); 344693936abSCsaba Dabis } 345693936abSCsaba Dabis 3460202c359SCsaba Dabis //===----------------------------------------------------------------------===// 3474d71600cSCsaba Dabis // Evaluating isa, isa_and_nonnull. 3484d71600cSCsaba Dabis //===----------------------------------------------------------------------===// 3494d71600cSCsaba Dabis 3504d71600cSCsaba Dabis void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV, 3514d71600cSCsaba Dabis CheckerContext &C) const { 3524d71600cSCsaba Dabis ProgramStateRef NonNullState, NullState; 3534d71600cSCsaba Dabis std::tie(NonNullState, NullState) = C.getState()->assume(DV); 3544d71600cSCsaba Dabis 3554d71600cSCsaba Dabis if (NonNullState) { 3564d71600cSCsaba Dabis addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true); 3574d71600cSCsaba Dabis addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false); 3584d71600cSCsaba Dabis } 3594d71600cSCsaba Dabis 3604d71600cSCsaba Dabis if (NullState) { 3614d71600cSCsaba Dabis C.generateSink(NullState, C.getPredecessor()); 3624d71600cSCsaba Dabis } 3634d71600cSCsaba Dabis } 3644d71600cSCsaba Dabis 3654d71600cSCsaba Dabis void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call, 3664d71600cSCsaba Dabis DefinedOrUnknownSVal DV, 3674d71600cSCsaba Dabis CheckerContext &C) const { 3684d71600cSCsaba Dabis ProgramStateRef NonNullState, NullState; 3694d71600cSCsaba Dabis std::tie(NonNullState, NullState) = C.getState()->assume(DV); 3704d71600cSCsaba Dabis 3714d71600cSCsaba Dabis if (NonNullState) { 3724d71600cSCsaba Dabis addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true); 3734d71600cSCsaba Dabis addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false); 3744d71600cSCsaba Dabis } 3754d71600cSCsaba Dabis 3764d71600cSCsaba Dabis if (NullState) { 3774d71600cSCsaba Dabis addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false); 3784d71600cSCsaba Dabis } 3794d71600cSCsaba Dabis } 3804d71600cSCsaba Dabis 3814d71600cSCsaba Dabis //===----------------------------------------------------------------------===// 3820202c359SCsaba Dabis // Main logic to evaluate a call. 3830202c359SCsaba Dabis //===----------------------------------------------------------------------===// 3840202c359SCsaba Dabis 385693936abSCsaba Dabis bool CastValueChecker::evalCall(const CallEvent &Call, 386693936abSCsaba Dabis CheckerContext &C) const { 387cf229d57SCsaba Dabis const auto *Lookup = CDM.lookup(Call); 388cf229d57SCsaba Dabis if (!Lookup) 389693936abSCsaba Dabis return false; 390693936abSCsaba Dabis 391cf229d57SCsaba Dabis const CastCheck &Check = Lookup->first; 3920202c359SCsaba Dabis CallKind Kind = Lookup->second; 3934d71600cSCsaba Dabis 394cf229d57SCsaba Dabis Optional<DefinedOrUnknownSVal> DV; 395cf229d57SCsaba Dabis 396cf229d57SCsaba Dabis switch (Kind) { 3970202c359SCsaba Dabis case CallKind::Function: { 398af992e6dSArtem Dergachev // We only model casts from pointers to pointers or from references 399af992e6dSArtem Dergachev // to references. Other casts are most likely specialized and we 400af992e6dSArtem Dergachev // cannot model them. 401af992e6dSArtem Dergachev QualType ParamT = Call.parameters()[0]->getType(); 402af992e6dSArtem Dergachev QualType ResultT = Call.getResultType(); 403af992e6dSArtem Dergachev if (!(ParamT->isPointerType() && ResultT->isPointerType()) && 404af992e6dSArtem Dergachev !(ParamT->isReferenceType() && ResultT->isReferenceType())) 405693936abSCsaba Dabis return false; 406693936abSCsaba Dabis 407cf229d57SCsaba Dabis DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>(); 408cf229d57SCsaba Dabis break; 409cf229d57SCsaba Dabis } 4104d71600cSCsaba Dabis case CallKind::InstanceOf: { 4114d71600cSCsaba Dabis // We need to obtain the only template argument to determinte the type. 4124d71600cSCsaba Dabis const FunctionDecl *FD = Call.getDecl()->getAsFunction(); 4134d71600cSCsaba Dabis if (!FD || !FD->getTemplateSpecializationArgs()) 4144d71600cSCsaba Dabis return false; 4154d71600cSCsaba Dabis 4164d71600cSCsaba Dabis DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>(); 4174d71600cSCsaba Dabis break; 4184d71600cSCsaba Dabis } 4190202c359SCsaba Dabis case CallKind::Method: 420cf229d57SCsaba Dabis const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call); 421cf229d57SCsaba Dabis if (!InstanceCall) 422693936abSCsaba Dabis return false; 423693936abSCsaba Dabis 424cf229d57SCsaba Dabis DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>(); 425cf229d57SCsaba Dabis break; 426cf229d57SCsaba Dabis } 427cf229d57SCsaba Dabis 428cf229d57SCsaba Dabis if (!DV) 429693936abSCsaba Dabis return false; 430693936abSCsaba Dabis 4310202c359SCsaba Dabis Check(this, Call, *DV, C); 432693936abSCsaba Dabis return true; 433693936abSCsaba Dabis } 434693936abSCsaba Dabis 435693936abSCsaba Dabis void ento::registerCastValueChecker(CheckerManager &Mgr) { 436693936abSCsaba Dabis Mgr.registerChecker<CastValueChecker>(); 437693936abSCsaba Dabis } 438693936abSCsaba Dabis 439693936abSCsaba Dabis bool ento::shouldRegisterCastValueChecker(const LangOptions &LO) { 440693936abSCsaba Dabis return true; 441693936abSCsaba Dabis } 442