36 using namespace clang;
51 class DynamicTypePropagation:
52 public Checker< check::PreCall,
55 check::PostStmt<CastExpr>,
56 check::PostStmt<CXXNewExpr>,
57 check::PreObjCMessage,
58 check::PostObjCMessage > {
60 CheckerContext &C)
const;
64 CheckerContext &C)
const;
66 ExplodedNode *dynamicTypePropagationOnCasts(
const CastExpr *CE,
68 CheckerContext &C)
const;
70 mutable std::unique_ptr<BugType> ObjCGenericsBugType;
71 void initBugType()
const {
72 if (!ObjCGenericsBugType)
73 ObjCGenericsBugType.reset(
79 GenericsBugVisitor(
SymbolRef S) : Sym(S) {}
81 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
87 std::shared_ptr<PathDiagnosticPiece> VisitNode(
const ExplodedNode *N,
88 BugReporterContext &BRC,
89 BugReport &BR)
override;
99 const Stmt *ReportedNode =
nullptr)
const;
102 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
103 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
104 void checkPostStmt(
const CastExpr *CastE, CheckerContext &C)
const;
105 void checkPostStmt(
const CXXNewExpr *NewE, CheckerContext &C)
const;
106 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
107 void checkPreObjCMessage(
const ObjCMethodCall &M, CheckerContext &C)
const;
108 void checkPostObjCMessage(
const ObjCMethodCall &M, CheckerContext &C)
const;
111 DefaultBool CheckGenerics;
115 void DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR,
116 CheckerContext &C)
const {
119 for (DynamicTypeMapImpl::iterator I = TypeMap.begin(), E = TypeMap.end();
121 if (!SR.isLiveRegion(I->first)) {
122 State = State->remove<DynamicTypeMap>(I->first);
126 MostSpecializedTypeArgsMapTy TyArgMap =
127 State->get<MostSpecializedTypeArgsMap>();
128 for (MostSpecializedTypeArgsMapTy::iterator I = TyArgMap.begin(),
131 if (SR.isDead(I->first)) {
132 State = State->remove<MostSpecializedTypeArgsMap>(I->first);
136 C.addTransition(State);
149 C.addTransition(State);
152 void DynamicTypePropagation::checkPreCall(
const CallEvent &Call,
153 CheckerContext &C)
const {
163 switch (Ctor->getOriginExpr()->getConstructionKind()) {
170 if (
const MemRegion *
Target = Ctor->getCXXThisVal().getAsRegion())
180 if (!Dtor->isBaseDestructor())
183 const MemRegion *
Target = Dtor->getCXXThisVal().getAsRegion();
187 const Decl *D = Dtor->getDecl();
196 void DynamicTypePropagation::checkPostCall(
const CallEvent &Call,
197 CheckerContext &C)
const {
199 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
202 const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
210 switch (Msg->getMethodFamily()) {
221 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
225 C.getASTContext().getObjCObjectPointerType(
QualType(ObjTy, 0));
232 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
246 switch (Ctor->getOriginExpr()->getConstructionKind()) {
257 if (
const MemRegion *
Target = Ctor->getCXXThisVal().getAsRegion()) {
268 if (dyn_cast_or_null<InitListExpr>(
283 ExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts(
286 const MemRegion *ToR = C.getSVal(CE).getAsRegion();
288 return C.getPredecessor();
290 if (isa<ExplicitCastExpr>(CE))
291 return C.getPredecessor();
293 if (
const Type *NewTy = getBetterObjCType(CE, C)) {
295 return C.addTransition(
State);
297 return C.getPredecessor();
300 void DynamicTypePropagation::checkPostStmt(
const CXXNewExpr *NewE,
301 CheckerContext &C)
const {
306 const MemRegion *MR = C.getSVal(NewE).getAsRegion();
315 DynamicTypePropagation::getObjectTypeForAllocAndNew(
const ObjCMessageExpr *MsgE,
316 CheckerContext &C)
const {
334 if (
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
341 dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
352 DynamicTypePropagation::getBetterObjCType(
const Expr *CastE,
353 CheckerContext &C)
const {
354 const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
392 return MostInformativeCandidate;
404 const auto *SuperOfTo =
415 MostInformativeCandidate, C);
486 State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound);
492 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
508 if (WithMostInfo == *Current)
510 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
517 if (WithMostInfo != *Current) {
518 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
528 void DynamicTypePropagation::checkPostStmt(
const CastExpr *CE,
529 CheckerContext &C)
const {
539 if (!OrigObjectPtrType || !DestObjectPtrType)
543 ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State, C);
552 OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
555 if (OrigObjectPtrType->isUnspecialized() &&
559 SymbolRef Sym = C.getSVal(CE).getAsSymbol();
564 State->get<MostSpecializedTypeArgsMap>(Sym);
566 if (isa<ExplicitCastExpr>(CE)) {
576 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
577 C.addTransition(State, AfterTypeProp);
595 static CheckerProgramPointTag IllegalConv(
this,
"IllegalConversion");
596 ExplodedNode *N = C.addTransition(State, AfterTypeProp, &IllegalConv);
597 reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym, C);
605 if (OrigToDest && !DestToOrig)
606 std::swap(LowerBound, UpperBound);
609 LowerBound = LowerBound->
isObjCIdType() ? UpperBound : LowerBound;
610 UpperBound = UpperBound->
isObjCIdType() ? LowerBound : UpperBound;
614 C.addTransition(State, AfterTypeProp);
631 class IsObjCTypeParamDependentTypeVisitor
634 IsObjCTypeParamDependentTypeVisitor() : Result(
false) {}
636 if (isa<ObjCTypeParamDecl>(Type->
getDecl())) {
646 IsObjCTypeParamDependentTypeVisitor Visitor;
647 Visitor.TraverseType(Type);
648 return Visitor.Result;
662 const auto *ReceiverObjectPtrType =
712 void DynamicTypePropagation::checkPreObjCMessage(
const ObjCMethodCall &M,
713 CheckerContext &C)
const {
720 State->get<MostSpecializedTypeArgsMap>(Sym);
774 for (
unsigned i = 0; i < Method->
param_size(); i++) {
786 const auto *ArgObjectPtrType =
788 if (!ParamObjectPtrType || !ArgObjectPtrType)
793 SVal ArgSVal = M.getArgSVal(i);
794 SymbolRef ArgSym = ArgSVal.getAsSymbol();
797 State->get<MostSpecializedTypeArgsMap>(ArgSym);
798 if (TrackedArgType &&
800 ArgObjectPtrType = *TrackedArgType;
807 static CheckerProgramPointTag Tag(
this,
"ArgTypeMismatch");
808 ExplodedNode *N = C.addTransition(State, &Tag);
809 reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg);
822 void DynamicTypePropagation::checkPostObjCMessage(
const ObjCMethodCall &M,
823 CheckerContext &C)
const {
826 SymbolRef RetSym = M.getReturnValue().getAsSymbol();
840 C.getASTContext().getObjCObjectPointerType(
843 if (!ReceiverClassType->isSpecialized())
845 const auto *InferredType =
847 assert(InferredType);
849 State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
850 C.addTransition(State);
860 State->get<MostSpecializedTypeArgsMap>(RecSym);
881 const MemRegion *RetRegion = M.getReturnValue().getAsRegion();
882 ExplodedNode *Pred = C.getPredecessor();
886 if (RetRegion && !State->get<DynamicTypeMap>(RetRegion)) {
892 Pred = C.addTransition(State);
897 if (!ResultPtrType || ResultPtrType->isUnspecialized())
902 if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) {
903 State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType);
904 C.addTransition(State, Pred);
908 void DynamicTypePropagation::reportGenericsBug(
910 ExplodedNode *N,
SymbolRef Sym, CheckerContext &C,
911 const Stmt *ReportedNode)
const {
917 llvm::raw_svector_ostream
OS(Buf);
918 OS <<
"Conversion from value of type '";
920 OS <<
"' to incompatible type '";
923 std::unique_ptr<BugReport> R(
924 new BugReport(*ObjCGenericsBugType, OS.str(), N));
925 R->markInteresting(Sym);
926 R->addVisitor(llvm::make_unique<GenericsBugVisitor>(Sym));
929 C.emitReport(std::move(R));
932 std::shared_ptr<PathDiagnosticPiece>
933 DynamicTypePropagation::GenericsBugVisitor::VisitNode(
const ExplodedNode *N,
934 BugReporterContext &BRC,
940 state->get<MostSpecializedTypeArgsMap>(Sym);
942 statePrev->get<MostSpecializedTypeArgsMap>(Sym);
946 if (TrackedTypePrev && *TrackedTypePrev == *TrackedType)
954 const LangOptions &LangOpts = BRC.getASTContext().getLangOpts();
957 llvm::raw_svector_ostream
OS(Buf);
960 OS <<
"' is inferred from ";
962 if (
const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
963 OS <<
"explicit cast (from '";
968 LangOpts, llvm::Twine());
970 }
else if (
const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
971 OS <<
"implicit cast (from '";
976 LangOpts, llvm::Twine());
979 OS <<
"this context";
983 PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
984 N->getLocationContext());
985 return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),
true,
990 void ento::registerObjCGenericsChecker(CheckerManager &mgr) {
991 DynamicTypePropagation *checker =
992 mgr.registerChecker<DynamicTypePropagation>();
993 checker->CheckGenerics =
true;
996 void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
997 mgr.registerChecker<DynamicTypePropagation>();
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
const char *const CoreFoundationObjectiveC
The receiver is an object instance.
Smart pointer class that efficiently represents Objective-C method names.
A (possibly-)qualified type.
QualType substObjCTypeArgs(ASTContext &ctx, ArrayRef< QualType > typeArgs, ObjCSubstitutionContext context) const
Substitute type arguments for the Objective-C type parameters used in the subject type...
unsigned param_size() const
Selector getSelector() const
ObjCInterfaceDecl * getClassInterface()
const SymExpr * SymbolRef
Stmt - This represents one statement.
Decl - This represents one declaration (or definition), e.g.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
ObjCTypeParamList * getTypeParamList() const
Retrieve the type parameters of this class.
The base class of the type hierarchy.
Stmt * getParent(Stmt *) const
bool isUnspecialized() const
Whether this type is unspecialized, meaning that is has no type arguments.
const T * getAs() const
Member-template getAs<specific type>'.
static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, CheckerContext &C)
ObjCMethodDecl - Represents an instance or class method declaration.
Represents a parameter to a function.
The collection of all-type qualifiers we support.
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.
Represents a class type in Objective C.
ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const
Lookup an instance method for a given selector.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool isObjCIdType() const
bool isSpecialized() const
Whether this type is specialized, meaning that it has type arguments.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
const ObjCObjectPointerType * stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const
Strip off the Objective-C "kindof" type and (with it) any protocol qualifiers.
static bool isObjCTypeParamDependent(QualType Type)
Represents any expression that calls an Objective-C method.
const ImplicitParamDecl * getSelfDecl() const
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
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, or null pointer when the returned type is not an ObjCObjectPointerType.
ObjCMethodDecl * lookupClassMethod(Selector Sel) const
Lookup a class method for a given selector.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Represents an ObjC class declaration.
QualType getReturnType() const
llvm::ImmutableMap< const MemRegion *, DynamicTypeInfo > DynamicTypeMapImpl
ObjCTypeParamDecl * getDecl() const
This represents one expression.
static bool storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, const ObjCObjectPointerType *const *Current, const ObjCObjectPointerType *StaticLowerBound, const ObjCObjectPointerType *StaticUpperBound, ASTContext &C)
Inputs:
Represents an implicit call to a C++ destructor.
bool hasRelatedResultType() const
Determine whether this method has a result type that is related to the message receiver's type...
bool isObjCClassType() const
DeclContext * getDeclContext()
bool isObjCIdType() const
True if this is equivalent to the 'id' type, i.e.
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg, DynamicTypeInfo NewTy)
Set dynamic type information of the region; return the new state.
An expression that sends a message to the given Objective-C object or class.
QualType getRecordType(const RecordDecl *Decl) const
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
The result type of a method or function.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
ParentMap & getParentMap() const
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class...
std::string getAsString() const
Derive the full selector name (e.g.
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
CastKind getCastKind() const
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)"...
Represents a static or instance method of a struct/union/class.
QualType getReceiverType() const
Retrieve the receiver type to which this message is being directed.
bool isSuperClassOf(const ObjCInterfaceDecl *I) const
isSuperClassOf - Return true if this class is the specified class or is a super class of the specifie...
QualType getSuperClassType() const
Retrieve the type of the superclass of this object type.
const ObjCMethodDecl * getMethodDecl() const
QualType getObjCInstanceType()
Retrieve the Objective-C "instancetype" type, if already known; otherwise, returns a NULL type;...
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
static const ObjCObjectPointerType * getMostInformativeDerivedClassImpl(const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, const ObjCObjectPointerType *MostInformativeCandidate, ASTContext &C)
virtual const ObjCMessageExpr * getOriginExpr() const
Dataflow Directional Tag Classes.
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg)
Get dynamic type information for a region.
QualType getSuperType() const
Retrieve the type referred to by 'super'.
Represents the declaration of an Objective-C type parameter.
const CXXRecordDecl * getParent() const
Returns the parent of this method declaration, which is the class in which this method is defined...
const ObjCObjectType * getObjectType() const
Gets the type pointed to by this ObjC pointer.
const Decl * getDecl() const
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
Represents a pointer to an Objective C object.
REGISTER_MAP_WITH_PROGRAMSTATE(MostSpecializedTypeArgsMap, SymbolRef, const ObjCObjectPointerType *) namespace
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface...
const StackFrameContext * getStackFrame() const
ObjCInterfaceDecl * getCanonicalDecl() override
Retrieves the canonical declaration of this Objective-C class.
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT)
canAssignObjCInterfaces - Return true if the two interface types are compatible for assignment from R...
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Represents a type parameter type in Objective C.
static const ObjCObjectPointerType * getMostInformativeDerivedClass(const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, ASTContext &C)
A downcast may loose specialization information.
The parameter type of a method or function.
static const Expr * stripCastsAndSugar(const Expr *E)
Stores a list of Objective-C type parameters for a parameterized class or a category/extension thereo...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
A reference to a declared variable, function, enum, etc.
QualType getObjCObjectPointerType(QualType OIT) const
Return a ObjCObjectPointerType type for the given ObjCObjectType.
The receiver is a superclass.
Represents a call to a C++ constructor.
The parameter is invariant: must match exactly.
Defines enum values for all the target-independent builtin functions.
ArrayRef< ParmVarDecl * > parameters() const