26 #include "llvm/ADT/Optional.h" 29 using namespace clang;
33 class CastValueChecker :
public Checker<eval::Call> {
34 enum class CallKind {
Function, Method, InstanceOf };
37 std::function<void(
const CastValueChecker *,
const CallEvent &Call,
38 DefinedOrUnknownSVal, CheckerContext &)>;
53 bool evalCall(
const CallEvent &Call, CheckerContext &C)
const;
59 {{{
"llvm",
"cast"}, 1},
61 {{{
"llvm",
"dyn_cast"}, 1},
62 {&CastValueChecker::evalDynCast, CallKind::Function}},
63 {{{
"llvm",
"cast_or_null"}, 1},
64 {&CastValueChecker::evalCastOrNull, CallKind::Function}},
65 {{{
"llvm",
"dyn_cast_or_null"}, 1},
66 {&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
67 {{{
"clang",
"castAs"}, 0},
68 {&CastValueChecker::evalCastAs, CallKind::Method}},
69 {{{
"clang",
"getAs"}, 0},
70 {&CastValueChecker::evalGetAs, CallKind::Method}},
71 {{{
"llvm",
"isa"}, 1},
72 {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
73 {{{
"llvm",
"isa_and_nonnull"}, 1},
74 {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
76 void evalCast(
const CallEvent &Call, DefinedOrUnknownSVal DV,
77 CheckerContext &C)
const;
78 void evalDynCast(
const CallEvent &Call, DefinedOrUnknownSVal DV,
79 CheckerContext &C)
const;
80 void evalCastOrNull(
const CallEvent &Call, DefinedOrUnknownSVal DV,
81 CheckerContext &C)
const;
82 void evalDynCastOrNull(
const CallEvent &Call, DefinedOrUnknownSVal DV,
83 CheckerContext &C)
const;
84 void evalCastAs(
const CallEvent &Call, DefinedOrUnknownSVal DV,
85 CheckerContext &C)
const;
86 void evalGetAs(
const CallEvent &Call, DefinedOrUnknownSVal DV,
87 CheckerContext &C)
const;
88 void evalIsa(
const CallEvent &Call, DefinedOrUnknownSVal DV,
89 CheckerContext &C)
const;
90 void evalIsaAndNonNull(
const CallEvent &Call, DefinedOrUnknownSVal DV,
91 CheckerContext &C)
const;
100 return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds();
104 const DynamicCastInfo *CastInfo,
106 bool CastSucceeds,
bool IsKnownCast) {
107 std::string CastToName =
108 CastInfo ? CastInfo->to()->getPointeeCXXRecordDecl()->getNameAsString()
113 [=]() -> std::string {
115 llvm::raw_svector_ostream Out(Msg);
120 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
121 Out <<
'\'' << DRE->getDecl()->getNameAsString() <<
'\'';
122 }
else if (
const auto *ME = dyn_cast<MemberExpr>(Object)) {
123 Out << (IsKnownCast ?
"Field '" :
"field '")
124 << ME->getMemberDecl()->getNameAsString() <<
'\'';
126 Out << (IsKnownCast ?
"The object" :
"the object");
129 Out <<
' ' << (CastSucceeds ?
"is a" :
"is not a") <<
" '" << CastToName
152 llvm_unreachable(
"Must align towards a reference type!");
156 CheckerContext &C,
bool IsNonNullParam,
157 bool IsNonNullReturn,
158 bool IsCheckedCast =
false) {
165 QualType CastToTy = Call.getResultType();
167 if (Call.getNumArgs() > 0) {
168 Object = Call.getArgExpr(0);
169 CastFromTy = Call.parameters()[0]->getType();
171 Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
172 CastFromTy = Object->
getType();
184 const MemRegion *MR = DV.getAsRegion();
185 const DynamicCastInfo *CastInfo =
189 bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
192 CastSucceeds = IsNonNullReturn && CastInfo->succeeds();
194 CastSucceeds = IsNonNullReturn;
199 C.generateSink(State, C.getPredecessor());
204 bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
205 if (!IsKnownCast || IsCheckedCast)
209 SVal
V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
210 : C.getSValBuilder().makeNull();
212 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
V,
false),
213 getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
217 DefinedOrUnknownSVal DV,
220 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
221 QualType CastFromTy = Call.parameters()[0]->getType();
224 CastToTy = C.getASTContext().getPointerType(CastToTy);
230 const MemRegion *MR = DV.getAsRegion();
231 const DynamicCastInfo *CastInfo =
236 CastSucceeds = IsInstanceOf && CastInfo->succeeds();
238 CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
241 C.generateSink(State, C.getPredecessor());
246 bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
252 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
253 C.getSValBuilder().makeTruthVal(CastSucceeds)),
254 getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
263 DefinedOrUnknownSVal DV,
265 bool IsCheckedCast =
false) {
267 true, IsCheckedCast);
271 DefinedOrUnknownSVal DV,
278 DefinedOrUnknownSVal DV,
281 C.addTransition(
State->BindExpr(Call.getOriginExpr(),
282 C.getLocationContext(),
283 C.getSValBuilder().makeNull(),
false),
284 C.getNoteTag(
"Assuming null pointer is passed into cast",
288 void CastValueChecker::evalCast(
const CallEvent &Call, DefinedOrUnknownSVal DV,
289 CheckerContext &C)
const {
293 void CastValueChecker::evalDynCast(
const CallEvent &Call,
294 DefinedOrUnknownSVal DV,
295 CheckerContext &C)
const {
300 void CastValueChecker::evalCastOrNull(
const CallEvent &Call,
301 DefinedOrUnknownSVal DV,
302 CheckerContext &C)
const {
307 void CastValueChecker::evalDynCastOrNull(
const CallEvent &Call,
308 DefinedOrUnknownSVal DV,
309 CheckerContext &C)
const {
320 DefinedOrUnknownSVal DV,
322 bool IsCheckedCast =
false) {
324 true, IsCheckedCast);
328 DefinedOrUnknownSVal DV,
334 void CastValueChecker::evalCastAs(
const CallEvent &Call,
335 DefinedOrUnknownSVal DV,
336 CheckerContext &C)
const {
340 void CastValueChecker::evalGetAs(
const CallEvent &Call, DefinedOrUnknownSVal DV,
341 CheckerContext &C)
const {
350 void CastValueChecker::evalIsa(
const CallEvent &Call, DefinedOrUnknownSVal DV,
351 CheckerContext &C)
const {
353 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
361 C.generateSink(NullState, C.getPredecessor());
365 void CastValueChecker::evalIsaAndNonNull(
const CallEvent &Call,
366 DefinedOrUnknownSVal DV,
367 CheckerContext &C)
const {
369 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
385 bool CastValueChecker::evalCall(
const CallEvent &Call,
386 CheckerContext &C)
const {
387 const auto *Lookup = CDM.lookup(Call);
391 const CastCheck &Check = Lookup->first;
392 CallKind
Kind = Lookup->second;
401 QualType ParamT = Call.parameters()[0]->getType();
402 QualType ResultT = Call.getResultType();
407 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
410 case CallKind::InstanceOf: {
412 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
416 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
419 case CallKind::Method:
424 DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
431 Check(
this, Call, *DV, C);
435 void ento::registerCastValueChecker(CheckerManager &Mgr) {
436 Mgr.registerChecker<CastValueChecker>();
439 bool ento::shouldRegisterCastValueChecker(
const LangOptions &LO) {
Represents a function declaration or definition.
A (possibly-)qualified type.
static void evalZeroParamNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C)
static void evalNonNullParamNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C)
void addConst()
Add the const type qualifier to this QualType.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type...
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Defines the C++ template declaration subclasses.
constexpr XRayInstrMask Function
static void evalZeroParamNonNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C, bool IsCheckedCast=false)
const DynamicCastInfo * getDynamicCastInfo(ProgramStateRef State, const MemRegion *MR, QualType CastFromTy, QualType CastToTy)
Get dynamic cast information from CastFromTy to CastToTy of MR.
const TemplateArgument & get(unsigned Idx) const
Retrieve the template argument at a given index.
static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C, bool IsNonNullParam, bool IsNonNullReturn, bool IsCheckedCast=false)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool isReferenceType() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
bool isRValueReferenceType() const
static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards, ASTContext &ACtx)
Represents a non-static C++ member function call, no matter how it is written.
This represents one expression.
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to...
const TemplateArgumentList * getTemplateSpecializationArgs() const
Retrieve the template arguments used to produce this function template specialization from the primar...
static const NoteTag * getNoteTag(CheckerContext &C, const DynamicCastInfo *CastInfo, QualType CastToTy, const Expr *Object, bool CastSucceeds, bool IsKnownCast)
bool isConstQualified() const
Determine whether this type is const-qualified.
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...
Dataflow Directional Tag Classes.
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.
static void evalNullParamNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C)
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
bool isLValueReferenceType() const
static bool isInfeasibleCast(const DynamicCastInfo *CastInfo, bool CastSucceeds)
QualType getRValueReferenceType(QualType T) const
Return the uniqued reference to the type for an rvalue reference to the specified type...
QualType getAsType() const
Retrieve the type for a type template argument.
An immutable map from CallDescriptions to arbitrary data.
bool isPointerType() const
static void evalNonNullParamNonNullReturn(const CallEvent &Call, DefinedOrUnknownSVal DV, CheckerContext &C, bool IsCheckedCast=false)
static void addInstanceOfTransition(const CallEvent &Call, DefinedOrUnknownSVal DV, ProgramStateRef State, CheckerContext &C, bool IsInstanceOf)