10b57cec5SDimitry Andric //===- CastValueChecker - Model implementation of custom RTTIs --*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This defines CastValueChecker which models casts of custom RTTIs. 100b57cec5SDimitry Andric // 11a7dea167SDimitry Andric // TODO list: 12a7dea167SDimitry Andric // - It only allows one succesful cast between two types however in the wild 13a7dea167SDimitry Andric // the object could be casted to multiple types. 14a7dea167SDimitry Andric // - It needs to check the most likely type information from the dynamic type 15a7dea167SDimitry Andric // map to increase precision of dynamic casting. 16a7dea167SDimitry Andric // 170b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 180b57cec5SDimitry Andric 19a7dea167SDimitry Andric #include "clang/AST/DeclTemplate.h" 200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 210b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 220b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 23349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 240b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 250b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 26a7dea167SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" 27bdd1243dSDimitry Andric #include <optional> 28a7dea167SDimitry Andric #include <utility> 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric using namespace clang; 310b57cec5SDimitry Andric using namespace ento; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric namespace { 345ffd83dbSDimitry Andric class CastValueChecker : public Checker<check::DeadSymbols, eval::Call> { 35a7dea167SDimitry Andric enum class CallKind { Function, Method, InstanceOf }; 36a7dea167SDimitry Andric 370b57cec5SDimitry Andric using CastCheck = 38a7dea167SDimitry Andric std::function<void(const CastValueChecker *, const CallEvent &Call, 390b57cec5SDimitry Andric DefinedOrUnknownSVal, CheckerContext &)>; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric public: 42a7dea167SDimitry Andric // We have five cases to evaluate a cast: 43a7dea167SDimitry Andric // 1) The parameter is non-null, the return value is non-null. 44a7dea167SDimitry Andric // 2) The parameter is non-null, the return value is null. 45a7dea167SDimitry Andric // 3) The parameter is null, the return value is null. 460b57cec5SDimitry Andric // cast: 1; dyn_cast: 1, 2; cast_or_null: 1, 3; dyn_cast_or_null: 1, 2, 3. 47a7dea167SDimitry Andric // 48a7dea167SDimitry Andric // 4) castAs: Has no parameter, the return value is non-null. 49a7dea167SDimitry Andric // 5) getAs: Has no parameter, the return value is null or non-null. 50a7dea167SDimitry Andric // 51a7dea167SDimitry Andric // We have two cases to check the parameter is an instance of the given type. 52a7dea167SDimitry Andric // 1) isa: The parameter is non-null, returns boolean. 53a7dea167SDimitry Andric // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean. 540b57cec5SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const; 555ffd83dbSDimitry Andric void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric private: 58a7dea167SDimitry Andric // These are known in the LLVM project. The pairs are in the following form: 59*0fca6ea1SDimitry Andric // {{match-mode, {namespace, call}, argument-count}, {callback, kind}} 60a7dea167SDimitry Andric const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = { 61*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"llvm", "cast"}, 1}, 62a7dea167SDimitry Andric {&CastValueChecker::evalCast, CallKind::Function}}, 63*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"llvm", "dyn_cast"}, 1}, 64a7dea167SDimitry Andric {&CastValueChecker::evalDynCast, CallKind::Function}}, 65*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"llvm", "cast_or_null"}, 1}, 66a7dea167SDimitry Andric {&CastValueChecker::evalCastOrNull, CallKind::Function}}, 67*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"llvm", "dyn_cast_or_null"}, 1}, 68a7dea167SDimitry Andric {&CastValueChecker::evalDynCastOrNull, CallKind::Function}}, 69*0fca6ea1SDimitry Andric {{CDM::CXXMethod, {"clang", "castAs"}, 0}, 70a7dea167SDimitry Andric {&CastValueChecker::evalCastAs, CallKind::Method}}, 71*0fca6ea1SDimitry Andric {{CDM::CXXMethod, {"clang", "getAs"}, 0}, 72a7dea167SDimitry Andric {&CastValueChecker::evalGetAs, CallKind::Method}}, 73*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"llvm", "isa"}, 1}, 74a7dea167SDimitry Andric {&CastValueChecker::evalIsa, CallKind::InstanceOf}}, 75*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"llvm", "isa_and_nonnull"}, 1}, 76a7dea167SDimitry Andric {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}}; 770b57cec5SDimitry Andric 78a7dea167SDimitry Andric void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV, 790b57cec5SDimitry Andric CheckerContext &C) const; 80a7dea167SDimitry Andric void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV, 810b57cec5SDimitry Andric CheckerContext &C) const; 82a7dea167SDimitry Andric void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV, 830b57cec5SDimitry Andric CheckerContext &C) const; 84a7dea167SDimitry Andric void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV, 85a7dea167SDimitry Andric CheckerContext &C) const; 86a7dea167SDimitry Andric void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV, 87a7dea167SDimitry Andric CheckerContext &C) const; 88a7dea167SDimitry Andric void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV, 89a7dea167SDimitry Andric CheckerContext &C) const; 90a7dea167SDimitry Andric void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV, 91a7dea167SDimitry Andric CheckerContext &C) const; 92a7dea167SDimitry Andric void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV, 930b57cec5SDimitry Andric CheckerContext &C) const; 940b57cec5SDimitry Andric }; 950b57cec5SDimitry Andric } // namespace 960b57cec5SDimitry Andric 97a7dea167SDimitry Andric static bool isInfeasibleCast(const DynamicCastInfo *CastInfo, 98a7dea167SDimitry Andric bool CastSucceeds) { 99a7dea167SDimitry Andric if (!CastInfo) 100a7dea167SDimitry Andric return false; 101a7dea167SDimitry Andric 102a7dea167SDimitry Andric return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds(); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 105a7dea167SDimitry Andric static const NoteTag *getNoteTag(CheckerContext &C, 106a7dea167SDimitry Andric const DynamicCastInfo *CastInfo, 107a7dea167SDimitry Andric QualType CastToTy, const Expr *Object, 108a7dea167SDimitry Andric bool CastSucceeds, bool IsKnownCast) { 109a7dea167SDimitry Andric std::string CastToName = 11016d6b3b3SDimitry Andric CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString() 11156f451bbSDimitry Andric : CastToTy.getAsString(); 112a7dea167SDimitry Andric Object = Object->IgnoreParenImpCasts(); 1130b57cec5SDimitry Andric 114a7dea167SDimitry Andric return C.getNoteTag( 115a7dea167SDimitry Andric [=]() -> std::string { 1160b57cec5SDimitry Andric SmallString<128> Msg; 1170b57cec5SDimitry Andric llvm::raw_svector_ostream Out(Msg); 1180b57cec5SDimitry Andric 119a7dea167SDimitry Andric if (!IsKnownCast) 120a7dea167SDimitry Andric Out << "Assuming "; 121a7dea167SDimitry Andric 122a7dea167SDimitry Andric if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) { 123e8d8bef9SDimitry Andric Out << '\'' << DRE->getDecl()->getDeclName() << '\''; 124a7dea167SDimitry Andric } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) { 125a7dea167SDimitry Andric Out << (IsKnownCast ? "Field '" : "field '") 126e8d8bef9SDimitry Andric << ME->getMemberDecl()->getDeclName() << '\''; 127a7dea167SDimitry Andric } else { 128a7dea167SDimitry Andric Out << (IsKnownCast ? "The object" : "the object"); 129a7dea167SDimitry Andric } 130a7dea167SDimitry Andric 131a7dea167SDimitry Andric Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName 132a7dea167SDimitry Andric << '\''; 133a7dea167SDimitry Andric 1345ffd83dbSDimitry Andric return std::string(Out.str()); 1350b57cec5SDimitry Andric }, 1360b57cec5SDimitry Andric /*IsPrunable=*/true); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 13916d6b3b3SDimitry Andric static const NoteTag *getNoteTag(CheckerContext &C, 14016d6b3b3SDimitry Andric SmallVector<QualType, 4> CastToTyVec, 14116d6b3b3SDimitry Andric const Expr *Object, 14216d6b3b3SDimitry Andric bool IsKnownCast) { 14316d6b3b3SDimitry Andric Object = Object->IgnoreParenImpCasts(); 14416d6b3b3SDimitry Andric 14516d6b3b3SDimitry Andric return C.getNoteTag( 14616d6b3b3SDimitry Andric [=]() -> std::string { 14716d6b3b3SDimitry Andric SmallString<128> Msg; 14816d6b3b3SDimitry Andric llvm::raw_svector_ostream Out(Msg); 14916d6b3b3SDimitry Andric 15016d6b3b3SDimitry Andric if (!IsKnownCast) 15116d6b3b3SDimitry Andric Out << "Assuming "; 15216d6b3b3SDimitry Andric 15316d6b3b3SDimitry Andric if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) { 15416d6b3b3SDimitry Andric Out << '\'' << DRE->getDecl()->getNameAsString() << '\''; 15516d6b3b3SDimitry Andric } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) { 15616d6b3b3SDimitry Andric Out << (IsKnownCast ? "Field '" : "field '") 15716d6b3b3SDimitry Andric << ME->getMemberDecl()->getNameAsString() << '\''; 15816d6b3b3SDimitry Andric } else { 15916d6b3b3SDimitry Andric Out << (IsKnownCast ? "The object" : "the object"); 16016d6b3b3SDimitry Andric } 16116d6b3b3SDimitry Andric Out << " is"; 16216d6b3b3SDimitry Andric 16316d6b3b3SDimitry Andric bool First = true; 16416d6b3b3SDimitry Andric for (QualType CastToTy: CastToTyVec) { 16516d6b3b3SDimitry Andric std::string CastToName = 16656f451bbSDimitry Andric CastToTy->getAsCXXRecordDecl() 16756f451bbSDimitry Andric ? CastToTy->getAsCXXRecordDecl()->getNameAsString() 16856f451bbSDimitry Andric : CastToTy.getAsString(); 16916d6b3b3SDimitry Andric Out << ' ' << ((CastToTyVec.size() == 1) ? "not" : 17016d6b3b3SDimitry Andric (First ? "neither" : "nor")) << " a '" << CastToName 17116d6b3b3SDimitry Andric << '\''; 17216d6b3b3SDimitry Andric First = false; 17316d6b3b3SDimitry Andric } 17416d6b3b3SDimitry Andric 17516d6b3b3SDimitry Andric return std::string(Out.str()); 17616d6b3b3SDimitry Andric }, 17716d6b3b3SDimitry Andric /*IsPrunable=*/true); 17816d6b3b3SDimitry Andric } 17916d6b3b3SDimitry Andric 180a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 181a7dea167SDimitry Andric // Main logic to evaluate a cast. 182a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 183a7dea167SDimitry Andric 184a7dea167SDimitry Andric static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards, 185a7dea167SDimitry Andric ASTContext &ACtx) { 186a7dea167SDimitry Andric if (alignTowards->isLValueReferenceType() && 187a7dea167SDimitry Andric alignTowards.isConstQualified()) { 188a7dea167SDimitry Andric toAlign.addConst(); 189a7dea167SDimitry Andric return ACtx.getLValueReferenceType(toAlign); 190a7dea167SDimitry Andric } else if (alignTowards->isLValueReferenceType()) 191a7dea167SDimitry Andric return ACtx.getLValueReferenceType(toAlign); 192a7dea167SDimitry Andric else if (alignTowards->isRValueReferenceType()) 193a7dea167SDimitry Andric return ACtx.getRValueReferenceType(toAlign); 194a7dea167SDimitry Andric 195a7dea167SDimitry Andric llvm_unreachable("Must align towards a reference type!"); 196a7dea167SDimitry Andric } 197a7dea167SDimitry Andric 198a7dea167SDimitry Andric static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV, 199a7dea167SDimitry Andric CheckerContext &C, bool IsNonNullParam, 200a7dea167SDimitry Andric bool IsNonNullReturn, 201a7dea167SDimitry Andric bool IsCheckedCast = false) { 202a7dea167SDimitry Andric ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam); 2030b57cec5SDimitry Andric if (!State) 2040b57cec5SDimitry Andric return; 2050b57cec5SDimitry Andric 206a7dea167SDimitry Andric const Expr *Object; 207a7dea167SDimitry Andric QualType CastFromTy; 208a7dea167SDimitry Andric QualType CastToTy = Call.getResultType(); 2090b57cec5SDimitry Andric 210a7dea167SDimitry Andric if (Call.getNumArgs() > 0) { 211a7dea167SDimitry Andric Object = Call.getArgExpr(0); 212a7dea167SDimitry Andric CastFromTy = Call.parameters()[0]->getType(); 213a7dea167SDimitry Andric } else { 214a7dea167SDimitry Andric Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr(); 215a7dea167SDimitry Andric CastFromTy = Object->getType(); 216a7dea167SDimitry Andric if (CastToTy->isPointerType()) { 217a7dea167SDimitry Andric if (!CastFromTy->isPointerType()) 218a7dea167SDimitry Andric return; 219a7dea167SDimitry Andric } else { 220a7dea167SDimitry Andric if (!CastFromTy->isReferenceType()) 2210b57cec5SDimitry Andric return; 2220b57cec5SDimitry Andric 223a7dea167SDimitry Andric CastFromTy = alignReferenceTypes(CastFromTy, CastToTy, C.getASTContext()); 224a7dea167SDimitry Andric } 225a7dea167SDimitry Andric } 2260b57cec5SDimitry Andric 227a7dea167SDimitry Andric const MemRegion *MR = DV.getAsRegion(); 228a7dea167SDimitry Andric const DynamicCastInfo *CastInfo = 229a7dea167SDimitry Andric getDynamicCastInfo(State, MR, CastFromTy, CastToTy); 230a7dea167SDimitry Andric 231a7dea167SDimitry Andric // We assume that every checked cast succeeds. 232a7dea167SDimitry Andric bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy; 233a7dea167SDimitry Andric if (!CastSucceeds) { 234a7dea167SDimitry Andric if (CastInfo) 235a7dea167SDimitry Andric CastSucceeds = IsNonNullReturn && CastInfo->succeeds(); 236a7dea167SDimitry Andric else 237a7dea167SDimitry Andric CastSucceeds = IsNonNullReturn; 238a7dea167SDimitry Andric } 239a7dea167SDimitry Andric 240a7dea167SDimitry Andric // Check for infeasible casts. 241a7dea167SDimitry Andric if (isInfeasibleCast(CastInfo, CastSucceeds)) { 242a7dea167SDimitry Andric C.generateSink(State, C.getPredecessor()); 243a7dea167SDimitry Andric return; 244a7dea167SDimitry Andric } 245a7dea167SDimitry Andric 246a7dea167SDimitry Andric // Store the type and the cast information. 247a7dea167SDimitry Andric bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy; 248a7dea167SDimitry Andric if (!IsKnownCast || IsCheckedCast) 249a7dea167SDimitry Andric State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy, 250a7dea167SDimitry Andric CastSucceeds); 251a7dea167SDimitry Andric 252a7dea167SDimitry Andric SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy) 25381ad6265SDimitry Andric : C.getSValBuilder().makeNullWithType(CastToTy); 254a7dea167SDimitry Andric C.addTransition( 255a7dea167SDimitry Andric State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false), 256a7dea167SDimitry Andric getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast)); 257a7dea167SDimitry Andric } 258a7dea167SDimitry Andric 259a7dea167SDimitry Andric static void addInstanceOfTransition(const CallEvent &Call, 260a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 261a7dea167SDimitry Andric ProgramStateRef State, CheckerContext &C, 262a7dea167SDimitry Andric bool IsInstanceOf) { 263a7dea167SDimitry Andric const FunctionDecl *FD = Call.getDecl()->getAsFunction(); 264a7dea167SDimitry Andric QualType CastFromTy = Call.parameters()[0]->getType(); 26516d6b3b3SDimitry Andric SmallVector<QualType, 4> CastToTyVec; 26616d6b3b3SDimitry Andric for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1; 26716d6b3b3SDimitry Andric ++idx) { 26816d6b3b3SDimitry Andric TemplateArgument CastToTempArg = 26916d6b3b3SDimitry Andric FD->getTemplateSpecializationArgs()->get(idx); 27016d6b3b3SDimitry Andric switch (CastToTempArg.getKind()) { 27116d6b3b3SDimitry Andric default: 27216d6b3b3SDimitry Andric return; 27316d6b3b3SDimitry Andric case TemplateArgument::Type: 27416d6b3b3SDimitry Andric CastToTyVec.push_back(CastToTempArg.getAsType()); 27516d6b3b3SDimitry Andric break; 27616d6b3b3SDimitry Andric case TemplateArgument::Pack: 27716d6b3b3SDimitry Andric for (TemplateArgument ArgInPack: CastToTempArg.pack_elements()) 27816d6b3b3SDimitry Andric CastToTyVec.push_back(ArgInPack.getAsType()); 27916d6b3b3SDimitry Andric break; 28016d6b3b3SDimitry Andric } 28116d6b3b3SDimitry Andric } 28216d6b3b3SDimitry Andric 28316d6b3b3SDimitry Andric const MemRegion *MR = DV.getAsRegion(); 28416d6b3b3SDimitry Andric if (MR && CastFromTy->isReferenceType()) 28516d6b3b3SDimitry Andric MR = State->getSVal(DV.castAs<Loc>()).getAsRegion(); 28616d6b3b3SDimitry Andric 28716d6b3b3SDimitry Andric bool Success = false; 28816d6b3b3SDimitry Andric bool IsAnyKnown = false; 28916d6b3b3SDimitry Andric for (QualType CastToTy: CastToTyVec) { 290a7dea167SDimitry Andric if (CastFromTy->isPointerType()) 291a7dea167SDimitry Andric CastToTy = C.getASTContext().getPointerType(CastToTy); 292a7dea167SDimitry Andric else if (CastFromTy->isReferenceType()) 293a7dea167SDimitry Andric CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext()); 294a7dea167SDimitry Andric else 295a7dea167SDimitry Andric return; 296a7dea167SDimitry Andric 297a7dea167SDimitry Andric const DynamicCastInfo *CastInfo = 298a7dea167SDimitry Andric getDynamicCastInfo(State, MR, CastFromTy, CastToTy); 299a7dea167SDimitry Andric 300a7dea167SDimitry Andric bool CastSucceeds; 301a7dea167SDimitry Andric if (CastInfo) 302a7dea167SDimitry Andric CastSucceeds = IsInstanceOf && CastInfo->succeeds(); 303a7dea167SDimitry Andric else 304a7dea167SDimitry Andric CastSucceeds = IsInstanceOf || CastFromTy == CastToTy; 305a7dea167SDimitry Andric 306a7dea167SDimitry Andric // Store the type and the cast information. 307a7dea167SDimitry Andric bool IsKnownCast = CastInfo || CastFromTy == CastToTy; 30816d6b3b3SDimitry Andric IsAnyKnown = IsAnyKnown || IsKnownCast; 30916d6b3b3SDimitry Andric ProgramStateRef NewState = State; 310a7dea167SDimitry Andric if (!IsKnownCast) 31116d6b3b3SDimitry Andric NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy, 312a7dea167SDimitry Andric IsInstanceOf); 313a7dea167SDimitry Andric 31416d6b3b3SDimitry Andric if (CastSucceeds) { 31516d6b3b3SDimitry Andric Success = true; 31616d6b3b3SDimitry Andric C.addTransition( 31716d6b3b3SDimitry Andric NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 31816d6b3b3SDimitry Andric C.getSValBuilder().makeTruthVal(true)), 31916d6b3b3SDimitry Andric getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true, 32016d6b3b3SDimitry Andric IsKnownCast)); 32116d6b3b3SDimitry Andric if (IsKnownCast) 32216d6b3b3SDimitry Andric return; 32316d6b3b3SDimitry Andric } else if (CastInfo && CastInfo->succeeds()) { 32416d6b3b3SDimitry Andric C.generateSink(NewState, C.getPredecessor()); 32516d6b3b3SDimitry Andric return; 32616d6b3b3SDimitry Andric } 32716d6b3b3SDimitry Andric } 32816d6b3b3SDimitry Andric 32916d6b3b3SDimitry Andric if (!Success) { 330a7dea167SDimitry Andric C.addTransition( 331a7dea167SDimitry Andric State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 33216d6b3b3SDimitry Andric C.getSValBuilder().makeTruthVal(false)), 33316d6b3b3SDimitry Andric getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown)); 33416d6b3b3SDimitry Andric } 335a7dea167SDimitry Andric } 336a7dea167SDimitry Andric 337a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 338a7dea167SDimitry Andric // Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null. 339a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 340a7dea167SDimitry Andric 341a7dea167SDimitry Andric static void evalNonNullParamNonNullReturn(const CallEvent &Call, 342a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 343a7dea167SDimitry Andric CheckerContext &C, 344a7dea167SDimitry Andric bool IsCheckedCast = false) { 345a7dea167SDimitry Andric addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 346a7dea167SDimitry Andric /*IsNonNullReturn=*/true, IsCheckedCast); 347a7dea167SDimitry Andric } 348a7dea167SDimitry Andric 349a7dea167SDimitry Andric static void evalNonNullParamNullReturn(const CallEvent &Call, 350a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 351a7dea167SDimitry Andric CheckerContext &C) { 352a7dea167SDimitry Andric addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 353a7dea167SDimitry Andric /*IsNonNullReturn=*/false); 354a7dea167SDimitry Andric } 355a7dea167SDimitry Andric 356a7dea167SDimitry Andric static void evalNullParamNullReturn(const CallEvent &Call, 357a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 358a7dea167SDimitry Andric CheckerContext &C) { 359a7dea167SDimitry Andric if (ProgramStateRef State = C.getState()->assume(DV, false)) 360a7dea167SDimitry Andric C.addTransition(State->BindExpr(Call.getOriginExpr(), 361a7dea167SDimitry Andric C.getLocationContext(), 36281ad6265SDimitry Andric C.getSValBuilder().makeNullWithType( 36381ad6265SDimitry Andric Call.getOriginExpr()->getType()), 36481ad6265SDimitry Andric false), 3650b57cec5SDimitry Andric C.getNoteTag("Assuming null pointer is passed into cast", 366a7dea167SDimitry Andric /*IsPrunable=*/true)); 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 369a7dea167SDimitry Andric void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV, 3700b57cec5SDimitry Andric CheckerContext &C) const { 371a7dea167SDimitry Andric evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true); 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 374a7dea167SDimitry Andric void CastValueChecker::evalDynCast(const CallEvent &Call, 375a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 3760b57cec5SDimitry Andric CheckerContext &C) const { 377a7dea167SDimitry Andric evalNonNullParamNonNullReturn(Call, DV, C); 378a7dea167SDimitry Andric evalNonNullParamNullReturn(Call, DV, C); 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric 381a7dea167SDimitry Andric void CastValueChecker::evalCastOrNull(const CallEvent &Call, 382a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 3830b57cec5SDimitry Andric CheckerContext &C) const { 384a7dea167SDimitry Andric evalNonNullParamNonNullReturn(Call, DV, C); 385a7dea167SDimitry Andric evalNullParamNullReturn(Call, DV, C); 3860b57cec5SDimitry Andric } 3870b57cec5SDimitry Andric 388a7dea167SDimitry Andric void CastValueChecker::evalDynCastOrNull(const CallEvent &Call, 389a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 3900b57cec5SDimitry Andric CheckerContext &C) const { 391a7dea167SDimitry Andric evalNonNullParamNonNullReturn(Call, DV, C); 392a7dea167SDimitry Andric evalNonNullParamNullReturn(Call, DV, C); 393a7dea167SDimitry Andric evalNullParamNullReturn(Call, DV, C); 3940b57cec5SDimitry Andric } 3950b57cec5SDimitry Andric 396a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 397a7dea167SDimitry Andric // Evaluating castAs, getAs. 398a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 399a7dea167SDimitry Andric 400a7dea167SDimitry Andric static void evalZeroParamNonNullReturn(const CallEvent &Call, 401a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 402a7dea167SDimitry Andric CheckerContext &C, 403a7dea167SDimitry Andric bool IsCheckedCast = false) { 404a7dea167SDimitry Andric addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 405a7dea167SDimitry Andric /*IsNonNullReturn=*/true, IsCheckedCast); 406a7dea167SDimitry Andric } 407a7dea167SDimitry Andric 408a7dea167SDimitry Andric static void evalZeroParamNullReturn(const CallEvent &Call, 409a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 410a7dea167SDimitry Andric CheckerContext &C) { 411a7dea167SDimitry Andric addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 412a7dea167SDimitry Andric /*IsNonNullReturn=*/false); 413a7dea167SDimitry Andric } 414a7dea167SDimitry Andric 415a7dea167SDimitry Andric void CastValueChecker::evalCastAs(const CallEvent &Call, 416a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 417a7dea167SDimitry Andric CheckerContext &C) const { 418a7dea167SDimitry Andric evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true); 419a7dea167SDimitry Andric } 420a7dea167SDimitry Andric 421a7dea167SDimitry Andric void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV, 422a7dea167SDimitry Andric CheckerContext &C) const { 423a7dea167SDimitry Andric evalZeroParamNonNullReturn(Call, DV, C); 424a7dea167SDimitry Andric evalZeroParamNullReturn(Call, DV, C); 425a7dea167SDimitry Andric } 426a7dea167SDimitry Andric 427a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 428a7dea167SDimitry Andric // Evaluating isa, isa_and_nonnull. 429a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 430a7dea167SDimitry Andric 431a7dea167SDimitry Andric void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV, 432a7dea167SDimitry Andric CheckerContext &C) const { 433a7dea167SDimitry Andric ProgramStateRef NonNullState, NullState; 434a7dea167SDimitry Andric std::tie(NonNullState, NullState) = C.getState()->assume(DV); 435a7dea167SDimitry Andric 436a7dea167SDimitry Andric if (NonNullState) { 437a7dea167SDimitry Andric addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true); 438a7dea167SDimitry Andric addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false); 439a7dea167SDimitry Andric } 440a7dea167SDimitry Andric 441a7dea167SDimitry Andric if (NullState) { 442a7dea167SDimitry Andric C.generateSink(NullState, C.getPredecessor()); 443a7dea167SDimitry Andric } 444a7dea167SDimitry Andric } 445a7dea167SDimitry Andric 446a7dea167SDimitry Andric void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call, 447a7dea167SDimitry Andric DefinedOrUnknownSVal DV, 448a7dea167SDimitry Andric CheckerContext &C) const { 449a7dea167SDimitry Andric ProgramStateRef NonNullState, NullState; 450a7dea167SDimitry Andric std::tie(NonNullState, NullState) = C.getState()->assume(DV); 451a7dea167SDimitry Andric 452a7dea167SDimitry Andric if (NonNullState) { 453a7dea167SDimitry Andric addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true); 454a7dea167SDimitry Andric addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false); 455a7dea167SDimitry Andric } 456a7dea167SDimitry Andric 457a7dea167SDimitry Andric if (NullState) { 458a7dea167SDimitry Andric addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false); 459a7dea167SDimitry Andric } 460a7dea167SDimitry Andric } 461a7dea167SDimitry Andric 462a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 463a7dea167SDimitry Andric // Main logic to evaluate a call. 464a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 465a7dea167SDimitry Andric 4660b57cec5SDimitry Andric bool CastValueChecker::evalCall(const CallEvent &Call, 4670b57cec5SDimitry Andric CheckerContext &C) const { 468a7dea167SDimitry Andric const auto *Lookup = CDM.lookup(Call); 469a7dea167SDimitry Andric if (!Lookup) 4700b57cec5SDimitry Andric return false; 4710b57cec5SDimitry Andric 472a7dea167SDimitry Andric const CastCheck &Check = Lookup->first; 473a7dea167SDimitry Andric CallKind Kind = Lookup->second; 474a7dea167SDimitry Andric 475bdd1243dSDimitry Andric std::optional<DefinedOrUnknownSVal> DV; 476a7dea167SDimitry Andric 477a7dea167SDimitry Andric switch (Kind) { 478a7dea167SDimitry Andric case CallKind::Function: { 479a7dea167SDimitry Andric // We only model casts from pointers to pointers or from references 480a7dea167SDimitry Andric // to references. Other casts are most likely specialized and we 481a7dea167SDimitry Andric // cannot model them. 482a7dea167SDimitry Andric QualType ParamT = Call.parameters()[0]->getType(); 483a7dea167SDimitry Andric QualType ResultT = Call.getResultType(); 484a7dea167SDimitry Andric if (!(ParamT->isPointerType() && ResultT->isPointerType()) && 48516d6b3b3SDimitry Andric !(ParamT->isReferenceType() && ResultT->isReferenceType())) { 4860b57cec5SDimitry Andric return false; 48716d6b3b3SDimitry Andric } 4880b57cec5SDimitry Andric 489a7dea167SDimitry Andric DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>(); 490a7dea167SDimitry Andric break; 491a7dea167SDimitry Andric } 492a7dea167SDimitry Andric case CallKind::InstanceOf: { 493a7dea167SDimitry Andric // We need to obtain the only template argument to determinte the type. 494a7dea167SDimitry Andric const FunctionDecl *FD = Call.getDecl()->getAsFunction(); 495a7dea167SDimitry Andric if (!FD || !FD->getTemplateSpecializationArgs()) 4960b57cec5SDimitry Andric return false; 4970b57cec5SDimitry Andric 498a7dea167SDimitry Andric DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>(); 499a7dea167SDimitry Andric break; 500a7dea167SDimitry Andric } 501a7dea167SDimitry Andric case CallKind::Method: 502a7dea167SDimitry Andric const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call); 503a7dea167SDimitry Andric if (!InstanceCall) 5040b57cec5SDimitry Andric return false; 5050b57cec5SDimitry Andric 506a7dea167SDimitry Andric DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>(); 507a7dea167SDimitry Andric break; 508a7dea167SDimitry Andric } 509a7dea167SDimitry Andric 510a7dea167SDimitry Andric if (!DV) 511a7dea167SDimitry Andric return false; 512a7dea167SDimitry Andric 513a7dea167SDimitry Andric Check(this, Call, *DV, C); 5140b57cec5SDimitry Andric return true; 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric 5175ffd83dbSDimitry Andric void CastValueChecker::checkDeadSymbols(SymbolReaper &SR, 5185ffd83dbSDimitry Andric CheckerContext &C) const { 5195ffd83dbSDimitry Andric C.addTransition(removeDeadCasts(C.getState(), SR)); 5205ffd83dbSDimitry Andric } 5215ffd83dbSDimitry Andric 5220b57cec5SDimitry Andric void ento::registerCastValueChecker(CheckerManager &Mgr) { 5230b57cec5SDimitry Andric Mgr.registerChecker<CastValueChecker>(); 5240b57cec5SDimitry Andric } 5250b57cec5SDimitry Andric 5265ffd83dbSDimitry Andric bool ento::shouldRegisterCastValueChecker(const CheckerManager &mgr) { 5270b57cec5SDimitry Andric return true; 5280b57cec5SDimitry Andric } 529