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