35 using namespace clang;
50 class DynamicTypePropagation:
51 public Checker< check::PreCall,
54 check::PostStmt<CastExpr>,
55 check::PostStmt<CXXNewExpr>,
56 check::PreObjCMessage,
57 check::PostObjCMessage > {
59 CheckerContext &C)
const;
63 CheckerContext &C)
const;
65 ExplodedNode *dynamicTypePropagationOnCasts(
const CastExpr *CE,
67 CheckerContext &C)
const;
69 mutable std::unique_ptr<BugType> ObjCGenericsBugType;
70 void initBugType()
const {
71 if (!ObjCGenericsBugType)
72 ObjCGenericsBugType.reset(
78 GenericsBugVisitor(
SymbolRef S) : Sym(S) {}
80 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
86 std::shared_ptr<PathDiagnosticPiece> VisitNode(
const ExplodedNode *N,
87 BugReporterContext &BRC,
88 BugReport &BR)
override;
98 const Stmt *ReportedNode =
nullptr)
const;
101 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
102 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
103 void checkPostStmt(
const CastExpr *CastE, CheckerContext &C)
const;
104 void checkPostStmt(
const CXXNewExpr *NewE, CheckerContext &C)
const;
105 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
106 void checkPreObjCMessage(
const ObjCMethodCall &M, CheckerContext &C)
const;
107 void checkPostObjCMessage(
const ObjCMethodCall &M, CheckerContext &C)
const;
110 DefaultBool CheckGenerics;
114 void DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR,
115 CheckerContext &C)
const {
118 for (DynamicTypeMapTy::iterator I = TypeMap.begin(), E = TypeMap.end();
120 if (!SR.isLiveRegion(I->first)) {
121 State = State->remove<DynamicTypeMap>(I->first);
125 MostSpecializedTypeArgsMapTy TyArgMap =
126 State->get<MostSpecializedTypeArgsMap>();
127 for (MostSpecializedTypeArgsMapTy::iterator I = TyArgMap.begin(),
130 if (SR.isDead(I->first)) {
131 State = State->remove<MostSpecializedTypeArgsMap>(I->first);
135 C.addTransition(State);
148 C.addTransition(State);
151 void DynamicTypePropagation::checkPreCall(
const CallEvent &Call,
152 CheckerContext &C)
const {
162 switch (Ctor->getOriginExpr()->getConstructionKind()) {
169 if (
const MemRegion *
Target = Ctor->getCXXThisVal().getAsRegion())
179 if (!Dtor->isBaseDestructor())
182 const MemRegion *
Target = Dtor->getCXXThisVal().getAsRegion();
186 const Decl *D = Dtor->getDecl();
195 void DynamicTypePropagation::checkPostCall(
const CallEvent &Call,
196 CheckerContext &C)
const {
198 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
201 const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
209 switch (Msg->getMethodFamily()) {
220 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
224 C.getASTContext().getObjCObjectPointerType(
QualType(ObjTy, 0));
231 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
245 switch (Ctor->getOriginExpr()->getConstructionKind()) {
256 if (
const MemRegion *
Target = Ctor->getCXXThisVal().getAsRegion()) {
267 if (dyn_cast_or_null<InitListExpr>(
282 ExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts(
285 const MemRegion *ToR = C.getSVal(CE).getAsRegion();
287 return C.getPredecessor();
289 if (isa<ExplicitCastExpr>(CE))
290 return C.getPredecessor();
292 if (
const Type *NewTy = getBetterObjCType(CE, C)) {
294 return C.addTransition(
State);
296 return C.getPredecessor();
299 void DynamicTypePropagation::checkPostStmt(
const CXXNewExpr *NewE,
300 CheckerContext &C)
const {
305 const MemRegion *MR = C.getSVal(NewE).getAsRegion();
314 DynamicTypePropagation::getObjectTypeForAllocAndNew(
const ObjCMessageExpr *MsgE,
315 CheckerContext &C)
const {
333 if (
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
340 dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
351 DynamicTypePropagation::getBetterObjCType(
const Expr *CastE,
352 CheckerContext &C)
const {
353 const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
391 return MostInformativeCandidate;
403 const auto *SuperOfTo =
414 MostInformativeCandidate, C);
485 State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound);
491 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
507 if (WithMostInfo == *Current)
509 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
516 if (WithMostInfo != *Current) {
517 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
527 void DynamicTypePropagation::checkPostStmt(
const CastExpr *CE,
528 CheckerContext &C)
const {
538 if (!OrigObjectPtrType || !DestObjectPtrType)
542 ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State, C);
551 OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
554 if (OrigObjectPtrType->isUnspecialized() &&
558 SymbolRef Sym = C.getSVal(CE).getAsSymbol();
563 State->get<MostSpecializedTypeArgsMap>(Sym);
565 if (isa<ExplicitCastExpr>(CE)) {
575 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
576 C.addTransition(State, AfterTypeProp);
594 static CheckerProgramPointTag IllegalConv(
this,
"IllegalConversion");
595 ExplodedNode *N = C.addTransition(State, AfterTypeProp, &IllegalConv);
596 reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym, C);
604 if (OrigToDest && !DestToOrig)
605 std::swap(LowerBound, UpperBound);
608 LowerBound = LowerBound->
isObjCIdType() ? UpperBound : LowerBound;
609 UpperBound = UpperBound->
isObjCIdType() ? LowerBound : UpperBound;
613 C.addTransition(State, AfterTypeProp);
630 class IsObjCTypeParamDependentTypeVisitor
633 IsObjCTypeParamDependentTypeVisitor() : Result(
false) {}
635 if (isa<ObjCTypeParamDecl>(Type->
getDecl())) {
645 IsObjCTypeParamDependentTypeVisitor Visitor;
646 Visitor.TraverseType(Type);
647 return Visitor.Result;
661 const auto *ReceiverObjectPtrType =
711 void DynamicTypePropagation::checkPreObjCMessage(
const ObjCMethodCall &M,
712 CheckerContext &C)
const {
719 State->get<MostSpecializedTypeArgsMap>(Sym);
785 const auto *ArgObjectPtrType =
787 if (!ParamObjectPtrType || !ArgObjectPtrType)
792 SVal ArgSVal = M.getArgSVal(
i);
793 SymbolRef ArgSym = ArgSVal.getAsSymbol();
796 State->get<MostSpecializedTypeArgsMap>(ArgSym);
797 if (TrackedArgType &&
799 ArgObjectPtrType = *TrackedArgType;
806 static CheckerProgramPointTag Tag(
this,
"ArgTypeMismatch");
807 ExplodedNode *N = C.addTransition(State, &Tag);
808 reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg);
821 void DynamicTypePropagation::checkPostObjCMessage(
const ObjCMethodCall &M,
822 CheckerContext &C)
const {
825 SymbolRef RetSym = M.getReturnValue().getAsSymbol();
839 C.getASTContext().getObjCObjectPointerType(
842 if (!ReceiverClassType->isSpecialized())
844 const auto *InferredType =
846 assert(InferredType);
848 State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
849 C.addTransition(State);
859 State->get<MostSpecializedTypeArgsMap>(RecSym);
880 const MemRegion *RetRegion = M.getReturnValue().getAsRegion();
881 ExplodedNode *Pred = C.getPredecessor();
885 if (RetRegion && !State->get<DynamicTypeMap>(RetRegion)) {
891 Pred = C.addTransition(State);
896 if (!ResultPtrType || ResultPtrType->isUnspecialized())
901 if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) {
902 State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType);
903 C.addTransition(State, Pred);
907 void DynamicTypePropagation::reportGenericsBug(
909 ExplodedNode *N,
SymbolRef Sym, CheckerContext &C,
910 const Stmt *ReportedNode)
const {
916 llvm::raw_svector_ostream
OS(Buf);
917 OS <<
"Conversion from value of type '";
919 OS <<
"' to incompatible type '";
922 std::unique_ptr<BugReport> R(
923 new BugReport(*ObjCGenericsBugType, OS.str(), N));
924 R->markInteresting(Sym);
925 R->addVisitor(llvm::make_unique<GenericsBugVisitor>(Sym));
928 C.emitReport(std::move(R));
931 std::shared_ptr<PathDiagnosticPiece>
932 DynamicTypePropagation::GenericsBugVisitor::VisitNode(
const ExplodedNode *N,
933 BugReporterContext &BRC,
939 state->get<MostSpecializedTypeArgsMap>(Sym);
941 statePrev->get<MostSpecializedTypeArgsMap>(Sym);
945 if (TrackedTypePrev && *TrackedTypePrev == *TrackedType)
953 const LangOptions &LangOpts = BRC.getASTContext().getLangOpts();
956 llvm::raw_svector_ostream
OS(Buf);
959 OS <<
"' is inferred from ";
961 if (
const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
962 OS <<
"explicit cast (from '";
967 LangOpts, llvm::Twine());
969 }
else if (
const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
970 OS <<
"implicit cast (from '";
975 LangOpts, llvm::Twine());
978 OS <<
"this context";
982 PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
983 N->getLocationContext());
984 return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),
true,
989 void ento::registerObjCGenericsChecker(CheckerManager &mgr) {
990 DynamicTypePropagation *checker = mgr.getChecker<DynamicTypePropagation>();
991 checker->CheckGenerics =
true;
994 bool ento::shouldRegisterObjCGenericsChecker(
const LangOptions &LO) {
998 void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
999 mgr.registerChecker<DynamicTypePropagation>();
1002 bool ento::shouldRegisterDynamicTypePropagation(
const LangOptions &LO) {
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
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.
llvm::ImmutableMap< const MemRegion *, DynamicTypeInfo > DynamicTypeMapTy
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
Return 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
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
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