34class CastValueChecker :
public Checker<check::DeadSymbols, eval::Call> {
35 enum class CallKind {
Function, Method, InstanceOf };
38 std::function<void(
const CastValueChecker *,
const CallEvent &
Call,
61 {{CDM::SimpleFunc, {
"llvm",
"cast"}, 1},
62 {&CastValueChecker::evalCast, CallKind::Function}},
63 {{CDM::SimpleFunc, {
"llvm",
"dyn_cast"}, 1},
64 {&CastValueChecker::evalDynCast, CallKind::Function}},
65 {{CDM::SimpleFunc, {
"llvm",
"cast_or_null"}, 1},
66 {&CastValueChecker::evalCastOrNull, CallKind::Function}},
67 {{CDM::SimpleFunc, {
"llvm",
"dyn_cast_or_null"}, 1},
68 {&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
69 {{CDM::CXXMethod, {
"clang",
"castAs"}, 0},
70 {&CastValueChecker::evalCastAs, CallKind::Method}},
71 {{CDM::CXXMethod, {
"clang",
"getAs"}, 0},
72 {&CastValueChecker::evalGetAs, CallKind::Method}},
73 {{CDM::SimpleFunc, {
"llvm",
"isa"}, 1},
74 {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
75 {{CDM::SimpleFunc, {
"llvm",
"isa_and_nonnull"}, 1},
76 {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
102 return CastSucceeds ? CastInfo->
fails() : CastInfo->
succeeds();
108 bool CastSucceeds,
bool IsKnownCast) {
109 std::string CastToName =
112 Object = Object->IgnoreParenImpCasts();
115 [=]() -> std::string {
117 llvm::raw_svector_ostream Out(Msg);
122 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
123 Out <<
'\'' << DRE->getDecl()->getDeclName() <<
'\'';
124 }
else if (
const auto *ME = dyn_cast<MemberExpr>(Object)) {
125 Out << (IsKnownCast ?
"Field '" :
"field '")
126 << ME->getMemberDecl()->getDeclName() <<
'\'';
128 Out << (IsKnownCast ?
"The object" :
"the object");
131 Out <<
' ' << (CastSucceeds ?
"is a" :
"is not a") <<
" '" << CastToName
134 return std::string(Out.str());
143 Object = Object->IgnoreParenImpCasts();
146 [=]() -> std::string {
148 llvm::raw_svector_ostream Out(Msg);
153 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
154 Out <<
'\'' << DRE->getDecl()->getNameAsString() <<
'\'';
155 }
else if (
const auto *ME = dyn_cast<MemberExpr>(Object)) {
156 Out << (IsKnownCast ?
"Field '" :
"field '")
157 << ME->getMemberDecl()->getNameAsString() <<
'\'';
159 Out << (IsKnownCast ?
"The object" :
"the object");
164 for (
QualType CastToTy: CastToTyVec) {
165 std::string CastToName =
166 CastToTy->getAsCXXRecordDecl()
167 ? CastToTy->getAsCXXRecordDecl()->getNameAsString()
168 : CastToTy.getAsString();
169 Out <<
' ' << ((CastToTyVec.size() == 1) ?
"not" :
170 (
First ?
"neither" :
"nor")) <<
" a '" << CastToName
175 return std::string(Out.str());
195 llvm_unreachable(
"Must align towards a reference type!");
200 bool IsNonNullReturn,
201 bool IsCheckedCast =
false) {
210 if (
Call.getNumArgs() > 0) {
211 Object =
Call.getArgExpr(0);
212 CastFromTy =
Call.parameters()[0]->getType();
214 Object = cast<CXXInstanceCall>(&
Call)->getCXXThisExpr();
215 CastFromTy = Object->getType();
232 bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
235 CastSucceeds = IsNonNullReturn && CastInfo->
succeeds();
237 CastSucceeds = IsNonNullReturn;
242 C.generateSink(State,
C.getPredecessor());
247 bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
248 if (!IsKnownCast || IsCheckedCast)
252 SVal V = CastSucceeds ?
C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
253 :
C.getSValBuilder().makeNullWithType(CastToTy);
255 State->BindExpr(
Call.getOriginExpr(),
C.getLocationContext(),
V,
false),
256 getNoteTag(
C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
270 switch (CastToTempArg.
getKind()) {
274 CastToTyVec.push_back(CastToTempArg.
getAsType());
278 CastToTyVec.push_back(ArgInPack.getAsType());
285 MR = State->getSVal(DV.
castAs<
Loc>()).getAsRegion();
288 bool IsAnyKnown =
false;
289 for (
QualType CastToTy: CastToTyVec) {
291 CastToTy =
C.getASTContext().getPointerType(CastToTy);
302 CastSucceeds = IsInstanceOf && CastInfo->
succeeds();
304 CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
307 bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
308 IsAnyKnown = IsAnyKnown || IsKnownCast;
317 NewState->BindExpr(
Call.getOriginExpr(),
C.getLocationContext(),
318 C.getSValBuilder().makeTruthVal(
true)),
323 }
else if (CastInfo && CastInfo->
succeeds()) {
324 C.generateSink(NewState,
C.getPredecessor());
331 State->BindExpr(
Call.getOriginExpr(),
C.getLocationContext(),
332 C.getSValBuilder().makeTruthVal(
false)),
344 bool IsCheckedCast =
false) {
346 true, IsCheckedCast);
360 C.addTransition(State->BindExpr(
Call.getOriginExpr(),
361 C.getLocationContext(),
362 C.getSValBuilder().makeNullWithType(
363 Call.getOriginExpr()->getType()),
365 C.getNoteTag(
"Assuming null pointer is passed into cast",
388void CastValueChecker::evalDynCastOrNull(
const CallEvent &
Call,
403 bool IsCheckedCast =
false) {
405 true, IsCheckedCast);
434 std::tie(NonNullState, NullState) =
C.getState()->assume(DV);
442 C.generateSink(NullState,
C.getPredecessor());
446void CastValueChecker::evalIsaAndNonNull(
const CallEvent &
Call,
450 std::tie(NonNullState, NullState) =
C.getState()->assume(DV);
468 const auto *Lookup =
CDM.lookup(
Call);
472 const CastCheck &Check = Lookup->first;
473 CallKind
Kind = Lookup->second;
475 std::optional<DefinedOrUnknownSVal> DV;
478 case CallKind::Function: {
492 case CallKind::InstanceOf: {
501 case CallKind::Method:
502 const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&
Call);
513 Check(
this,
Call, *DV,
C);
517void CastValueChecker::checkDeadSymbols(
SymbolReaper &SR,
526bool ento::shouldRegisterCastValueChecker(
const CheckerManager &mgr) {
static bool isInfeasibleCast(const DynamicCastInfo *CastInfo, bool CastSucceeds)
static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C, bool IsNonNullParam, bool IsNonNullReturn, bool IsCheckedCast=false)
static const NoteTag * getNoteTag(CheckerContext &C, const DynamicCastInfo *CastInfo, QualType CastToTy, const Expr *Object, bool CastSucceeds, bool IsKnownCast)
static void evalNonNullParamNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C)
static void addInstanceOfTransition(const CallEvent &Call, DefinedOrUnknownSVal DV, ProgramStateRef State, CheckerContext &C, bool IsInstanceOf)
static void evalZeroParamNonNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C, bool IsCheckedCast=false)
static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards, ASTContext &ACtx)
static void evalNullParamNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C)
static void evalZeroParamNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C)
static void evalNonNullParamNonNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C, bool IsCheckedCast=false)
Defines the C++ template declaration subclasses.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getRValueReferenceType(QualType T) const
Return the uniqued reference to the type for an rvalue reference to the specified type.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
This represents one expression.
Represents a function declaration or definition.
const TemplateArgumentList * getTemplateSpecializationArgs() const
Retrieve the template arguments used to produce this function template specialization from the primar...
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
A (possibly-)qualified type.
void addConst()
Add the const type qualifier to this QualType.
bool isConstQualified() const
Determine whether this type is const-qualified.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
const TemplateArgument & get(unsigned Idx) const
Retrieve the template argument at a given index.
Represents a template argument.
QualType getAsType() const
Retrieve the type for a type template argument.
ArrayRef< TemplateArgument > pack_elements() const
Iterator range referencing all of the elements of a template argument pack.
@ Pack
The template argument is actually a parameter pack.
@ Type
The template argument is a type.
ArgKind getKind() const
Return the kind of stored template argument.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isRValueReferenceType() const
bool isPointerType() const
bool isReferenceType() const
bool isLValueReferenceType() const
An immutable map from CallDescriptions to arbitrary data.
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
MemRegion - The root abstract class for all memory regions.
The tag upon which the TagVisitor reacts.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
const MemRegion * getAsRegion() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
A class responsible for cleaning up unused symbols.
const DynamicCastInfo * getDynamicCastInfo(ProgramStateRef State, const MemRegion *MR, QualType CastFromTy, QualType CastToTy)
Get dynamic cast information from CastFromTy to CastToTy of MR.
ProgramStateRef removeDeadCasts(ProgramStateRef State, SymbolReaper &SR)
Removes the dead cast informations from State.
ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State, const MemRegion *MR, QualType CastFromTy, QualType CastToTy, bool IsCastSucceeds)
Set dynamic type and cast information of the region; return the new state.
The JSON file list parser is used to communicate input to InstallAPI.
@ Success
Template argument deduction was successful.