34#include "llvm/ADT/STLExtras.h"
52class DynamicTypePropagation
53 :
public CheckerFamily<check::PreCall, check::PostCall, check::DeadSymbols,
54 check::PostStmt<CastExpr>,
55 check::PostStmt<CXXNewExpr>, check::PreObjCMessage,
56 check::PostObjCMessage> {
75 GenericsBugVisitor(
SymbolRef S) : Sym(S) {}
77 void Profile(llvm::FoldingSetNodeID &ID)
const override {
95 const Stmt *ReportedNode =
nullptr)
const;
107 StringRef
getDebugTag()
const override {
return "DynamicTypePropagation"; }
112 return PointerType->getObjectType()->isObjCClass();
119 bool Precise =
false;
121 operator bool()
const {
return Type !=
nullptr; }
155 if (
const auto *ObjTy =
157 return {ObjTy->getObjectType(),
true};
168 SVal ReceiverSVal =
C.getSVal(RecE);
178 if (InferredType.
isNull()) {
179 InferredType = ReceiverSymbol->getType();
184 if (isObjCClassType(InferredType)) {
193 SVal SelfSVal = State->getSelfSVal(
C.getLocationContext());
197 if (ReceiverSVal == SelfSVal) {
201 dyn_cast<ObjCMethodDecl>(
C.getStackFrame()->getDecl()))
203 MD->getClassInterface()->getTypeForDecl()))
210 if (InferredType.
isNull()) {
216 if (
const auto *ReceiverInferredType =
217 dyn_cast<ObjCObjectPointerType>(InferredType)) {
218 return {ReceiverInferredType->getObjectType()};
226void DynamicTypePropagation::checkDeadSymbols(
SymbolReaper &SR,
231 MostSpecializedTypeArgsMapTy TyArgMap =
232 State->get<MostSpecializedTypeArgsMap>();
233 for (
SymbolRef Sym : llvm::make_first_range(TyArgMap)) {
235 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
239 C.addTransition(State);
252 C.addTransition(State);
255void DynamicTypePropagation::checkPreCall(
const CallEvent &
Call,
266 switch (Ctor->getOriginExpr()->getConstructionKind()) {
283 if (!Dtor->isBaseDestructor())
290 const Decl *D = Dtor->getDecl();
299void DynamicTypePropagation::checkPostCall(
const CallEvent &
Call,
305 const MemRegion *RetReg =
Call.getReturnValue().getAsRegion();
313 switch (Msg->getMethodFamily()) {
323 RuntimeType ObjTy = inferReceiverType(*Msg,
C);
329 C.getASTContext().getObjCObjectPointerType(
QualType(ObjTy.Type, 0));
344 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
358 switch (Ctor->getOriginExpr()->getConstructionKind()) {
380 if (isa_and_nonnull<InitListExpr, CXXParenListInitExpr>(
395ExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts(
398 const MemRegion *ToR =
C.getSVal(CE).getAsRegion();
400 return C.getPredecessor();
403 return C.getPredecessor();
405 if (
const Type *NewTy = getBetterObjCType(CE,
C)) {
407 return C.addTransition(State);
409 return C.getPredecessor();
412void DynamicTypePropagation::checkPostStmt(
const CXXNewExpr *NewE,
418 const MemRegion *MR =
C.getSVal(NewE).getAsRegion();
430DynamicTypePropagation::getBetterObjCType(
const Expr *CastE,
432 const MemRegion *ToR =
C.getSVal(CastE).getAsRegion();
470 return MostInformativeCandidate;
482 const auto *SuperOfTo =
486 C.getObjCObjectPointerType(
QualType(SuperOfTo, 0));
493 MostInformativeCandidate,
C);
564 State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound);
570 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
575 if (
C.canAssignObjCInterfaces(StaticLowerBound, *Current)) {
580 if (
C.canAssignObjCInterfaces(*Current, StaticUpperBound)) {
586 if (WithMostInfo == *Current)
588 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
595 if (WithMostInfo != *Current) {
596 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
606void DynamicTypePropagation::checkPostStmt(
const CastExpr *CE,
617 if (!OrigObjectPtrType || !DestObjectPtrType)
621 ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State,
C);
630 OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
633 if (OrigObjectPtrType->isUnspecialized() &&
642 State->get<MostSpecializedTypeArgsMap>(Sym);
654 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
655 C.addTransition(State, AfterTypeProp);
678 "IllegalConversion");
680 C.generateNonFatalErrorNode(State, AfterTypeProp, &IllegalConv);
682 reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym,
C);
690 if (OrigToDest && !DestToOrig)
691 std::swap(LowerBound, UpperBound);
694 LowerBound = LowerBound->
isObjCIdType() ? UpperBound : LowerBound;
695 UpperBound = UpperBound->
isObjCIdType() ? LowerBound : UpperBound;
699 C.addTransition(State, AfterTypeProp);
716 class IsObjCTypeParamDependentTypeVisitor
719 IsObjCTypeParamDependentTypeVisitor() =
default;
720 bool VisitObjCTypeParamType(ObjCTypeParamType *
Type)
override {
731 IsObjCTypeParamDependentTypeVisitor Visitor;
732 Visitor.TraverseType(
Type);
733 return Visitor.Result;
778 QualType StaticResultType = Method->getReturnType();
781 if (StaticResultType ==
C.getObjCInstanceType())
796void DynamicTypePropagation::checkPreObjCMessage(
const ObjCMethodCall &M,
804 State->get<MostSpecializedTypeArgsMap>(Sym);
851 std::optional<ArrayRef<QualType>> TypeArgs =
852 (*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
858 for (
unsigned i = 0; i < Method->param_size(); i++) {
860 const ParmVarDecl *Param = Method->parameters()[i];
862 QualType OrigParamType = Param->getType();
870 const auto *ArgObjectPtrType =
872 if (!ParamObjectPtrType || !ArgObjectPtrType)
881 State->get<MostSpecializedTypeArgsMap>(ArgSym);
882 if (TrackedArgType &&
884 ArgObjectPtrType = *TrackedArgType;
892 reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym,
C, Arg);
905void DynamicTypePropagation::checkPostObjCMessage(
const ObjCMethodCall &M,
919 if (RuntimeType ReceiverRuntimeType = inferReceiverType(M,
C)) {
921 ReceiverRuntimeType.Type->getSuperClassType();
922 QualType ReceiverClassType(ReceiverRuntimeType.Type, 0);
925 if (ReceiverRuntimeType.Type->isSpecialized() &&
926 ReceiverRuntimeType.Precise) {
928 C.getASTContext().getObjCObjectPointerType(ReceiverClassType);
929 const auto *InferredType =
931 State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
936 !ReceiverRuntimeType.Precise);
938 C.addTransition(State);
946 if (RuntimeType ReceiverRuntimeType = inferReceiverType(M,
C)) {
950 ReceiverRuntimeType.Type->getSuperClassType();
956 if (!ReceiversSuperClass.
isNull()) {
959 State, RetSym, ReceiversSuperClass, !ReceiverRuntimeType.Precise);
961 C.addTransition(State);
973 State->get<MostSpecializedTypeArgsMap>(RecSym);
983 std::optional<ArrayRef<QualType>> TypeArgs =
984 (*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
1005 Pred =
C.addTransition(State);
1010 if (!ResultPtrType || ResultPtrType->isUnspecialized())
1015 if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) {
1016 State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType);
1017 C.addTransition(State, Pred);
1021void DynamicTypePropagation::reportGenericsBug(
1024 const Stmt *ReportedNode)
const {
1025 if (!ObjCGenericsChecker.isEnabled())
1029 llvm::raw_svector_ostream
OS(Buf);
1030 OS <<
"Conversion from value of type '";
1032 OS <<
"' to incompatible type '";
1035 auto R = std::make_unique<PathSensitiveBugReport>(ObjCGenericsChecker,
1037 R->markInteresting(Sym);
1038 R->addVisitor(std::make_unique<GenericsBugVisitor>(Sym));
1041 C.emitReport(std::move(R));
1051 state->get<MostSpecializedTypeArgsMap>(Sym);
1053 statePrev->get<MostSpecializedTypeArgsMap>(Sym);
1057 if (TrackedTypePrev && *TrackedTypePrev == *TrackedType)
1068 llvm::raw_svector_ostream
OS(Buf);
1071 OS <<
"' is inferred from ";
1073 if (
const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
1074 OS <<
"explicit cast (from '";
1079 LangOpts, llvm::Twine());
1081 }
else if (
const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
1082 OS <<
"implicit cast (from '";
1087 LangOpts, llvm::Twine());
1090 OS <<
"this context";
1096 return std::make_shared<PathDiagnosticEventPiece>(Pos,
OS.str(),
true);
1101 Mgr.
getChecker<DynamicTypePropagation>()->ObjCGenericsChecker.enable(Mgr);
1104bool ento::shouldRegisterObjCGenericsChecker(
const CheckerManager &) {
1116bool ento::shouldRegisterDynamicTypePropagation(
const CheckerManager &) {
Defines enum values for all the target-independent builtin functions.
static QualType getReturnTypeForMethod(const ObjCMethodDecl *Method, ArrayRef< QualType > TypeArgs, const ObjCObjectPointerType *SelfType, ASTContext &C)
Get the returned ObjCObjectPointerType by a method based on the tracked type information,...
static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, CheckerContext &C)
static const ObjCObjectPointerType * getMostInformativeDerivedClassImpl(const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, const ObjCObjectPointerType *MostInformativeCandidate, ASTContext &C)
static const ObjCMethodDecl * findMethodDecl(const ObjCMessageExpr *MessageExpr, const ObjCObjectPointerType *TrackedType, ASTContext &ASTCtxt)
A method might not be available in the interface indicated by the static type.
static bool isObjCTypeParamDependent(QualType Type)
static const Expr * stripCastsAndSugar(const Expr *E)
static const ObjCObjectPointerType * getMostInformativeDerivedClass(const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, ASTContext &C)
A downcast may loose specialization information.
static bool storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, const ObjCObjectPointerType *const *Current, const ObjCObjectPointerType *StaticLowerBound, const ObjCObjectPointerType *StaticUpperBound, ASTContext &C)
Inputs:
llvm::MachO::Target Target
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT)
canAssignObjCInterfaces - Return true if the two interface types are compatible for assignment from R...
const LangOptions & getLangOpts() const
CanQualType getCanonicalTagType(const TagDecl *TD) const
Represents a static or instance method of a struct/union/class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
CastKind getCastKind() const
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
const ParentMap & getParentMap() const
Represents an ObjC class declaration.
ObjCMethodDecl * lookupClassMethod(Selector Sel) const
Lookup a class method for a given selector.
ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const
Lookup an instance method for a given selector.
ObjCInterfaceDecl * getCanonicalDecl() override
Retrieves the canonical declaration of this Objective-C class.
bool isSuperClassOf(const ObjCInterfaceDecl *I) const
isSuperClassOf - Return true if this class is the specified class or is a super class of the specifie...
An expression that sends a message to the given Objective-C object or class.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Selector getSelector() const
@ SuperInstance
The receiver is the instance of the superclass object.
@ Instance
The receiver is an object instance.
@ SuperClass
The receiver is a superclass.
@ Class
The receiver is a class.
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
QualType getSuperType() const
Retrieve the type referred to by 'super'.
const ObjCMethodDecl * getMethodDecl() const
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
QualType getReceiverType() const
Retrieve the receiver type to which this message is being directed.
ObjCMethodDecl - Represents an instance or class method declaration.
bool hasRelatedResultType() const
Determine whether this method has a result type that is related to the message receiver's type.
Represents a pointer to an Objective C object.
bool isSpecialized() const
Whether this type is specialized, meaning that it has type arguments.
const ObjCObjectPointerType * stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const
Strip off the Objective-C "kindof" type and (with it) any protocol qualifiers.
const ObjCObjectType * getObjectType() const
Gets the type pointed to by this ObjC pointer.
bool isUnspecialized() const
Whether this type is unspecialized, meaning that is has no type arguments.
bool isObjCIdType() const
True if this is equivalent to the 'id' type, i.e.
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface.
Represents the declaration of an Objective-C type parameter.
Stores a list of Objective-C type parameters for a parameterized class or a category/extension thereo...
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Stmt * getParent(Stmt *) const
Represents a parameter to a function.
PointerType - C99 6.7.5.1 - Pointer Declarators.
virtual StringRef getDebugTag() const =0
The description of this program point which will be dumped for debugging purposes.
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
QualType getCanonicalType() const
QualType substObjCTypeArgs(ASTContext &ctx, ArrayRef< QualType > typeArgs, ObjCSubstitutionContext context) const
Substitute type arguments for the Objective-C type parameters used in the subject type.
The collection of all-type qualifiers we support.
Smart pointer class that efficiently represents Objective-C method names.
std::string getAsString() const
Derive the full selector name (e.g.
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
The base class of the type hierarchy.
const T * castAs() const
Member-template castAs<specific type>.
bool isObjCIdType() const
bool isObjCClassType() const
const T * getAs() const
Member-template getAs<specific type>'.
ASTContext & getASTContext() const
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
Represents a call to a C++ constructor.
Represents an implicit call to a C++ destructor.
Represents an abstract call to a function or method along a particular path.
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
SVal getReturnValue() const
Returns the return value of the call.
Checker families (where a single backend class implements multiple related frontends) should derive f...
Trivial convenience class for the common case when a certain checker frontend always uses the same bu...
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
Stores the currently inferred strictest bound on the runtime type of a region in a given state along ...
QualType getType() const
Returns the currently inferred upper bound on the runtime type.
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
MemRegion - The root abstract class for all memory regions.
Represents any expression that calls an Objective-C method.
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
const MemRegion * getAsRegion() const
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
const char *const CoreFoundationObjectiveC
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
ProgramStateRef setClassObjectDynamicTypeInfo(ProgramStateRef State, SymbolRef Sym, DynamicTypeInfo NewTy)
Set constraint on a type contained in a class object; return the new state.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
ProgramStateRef removeDeadClassObjectTypes(ProgramStateRef State, SymbolReaper &SR)
Removes the dead Class object type informations from State.
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR)
Get dynamic type information for the region MR.
const DynamicTypeInfo * getRawDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR)
Get raw dynamic type information for the region MR.
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR, DynamicTypeInfo NewTy)
Set dynamic type information of the region; return the new state.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR)
Removes the dead type informations from State.
DynamicTypeInfo getClassObjectDynamicTypeInfo(ProgramStateRef State, SymbolRef Sym)
Get dynamic type information stored in a class object represented by Sym.
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
@ Parameter
The parameter type of a method or function.
@ Result
The result type of a method or function.
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
@ Invariant
The parameter is invariant: must match exactly.
U cast(CodeGen::Address addr)
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.