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 {
87 BugReporterContext &BRC,
88 PathSensitiveBugReport &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 MostSpecializedTypeArgsMapTy TyArgMap =
119 State->get<MostSpecializedTypeArgsMap>();
120 for (MostSpecializedTypeArgsMapTy::iterator I = TyArgMap.begin(),
123 if (SR.isDead(I->first)) {
124 State = State->remove<MostSpecializedTypeArgsMap>(I->first);
128 C.addTransition(State);
141 C.addTransition(State);
144 void DynamicTypePropagation::checkPreCall(
const CallEvent &Call,
145 CheckerContext &C)
const {
155 switch (Ctor->getOriginExpr()->getConstructionKind()) {
162 if (
const MemRegion *
Target = Ctor->getCXXThisVal().getAsRegion())
172 if (!Dtor->isBaseDestructor())
175 const MemRegion *
Target = Dtor->getCXXThisVal().getAsRegion();
179 const Decl *D = Dtor->getDecl();
188 void DynamicTypePropagation::checkPostCall(
const CallEvent &Call,
189 CheckerContext &C)
const {
191 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
194 const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
202 switch (Msg->getMethodFamily()) {
213 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
217 C.getASTContext().getObjCObjectPointerType(
QualType(ObjTy, 0));
224 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
238 switch (Ctor->getOriginExpr()->getConstructionKind()) {
249 if (
const MemRegion *
Target = Ctor->getCXXThisVal().getAsRegion()) {
260 if (dyn_cast_or_null<InitListExpr>(
275 ExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts(
278 const MemRegion *ToR = C.getSVal(CE).getAsRegion();
280 return C.getPredecessor();
282 if (isa<ExplicitCastExpr>(CE))
283 return C.getPredecessor();
285 if (
const Type *NewTy = getBetterObjCType(CE, C)) {
287 return C.addTransition(
State);
289 return C.getPredecessor();
292 void DynamicTypePropagation::checkPostStmt(
const CXXNewExpr *NewE,
293 CheckerContext &C)
const {
298 const MemRegion *MR = C.getSVal(NewE).getAsRegion();
307 DynamicTypePropagation::getObjectTypeForAllocAndNew(
const ObjCMessageExpr *MsgE,
308 CheckerContext &C)
const {
326 if (
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
333 dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
344 DynamicTypePropagation::getBetterObjCType(
const Expr *CastE,
345 CheckerContext &C)
const {
346 const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
384 return MostInformativeCandidate;
396 const auto *SuperOfTo =
407 MostInformativeCandidate, C);
478 State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound);
484 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
500 if (WithMostInfo == *Current)
502 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
509 if (WithMostInfo != *Current) {
510 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
520 void DynamicTypePropagation::checkPostStmt(
const CastExpr *CE,
521 CheckerContext &C)
const {
531 if (!OrigObjectPtrType || !DestObjectPtrType)
535 ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State, C);
544 OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
547 if (OrigObjectPtrType->isUnspecialized() &&
551 SymbolRef Sym = C.getSVal(CE).getAsSymbol();
556 State->get<MostSpecializedTypeArgsMap>(Sym);
558 if (isa<ExplicitCastExpr>(CE)) {
568 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
569 C.addTransition(State, AfterTypeProp);
587 static CheckerProgramPointTag IllegalConv(
this,
"IllegalConversion");
588 ExplodedNode *N = C.addTransition(State, AfterTypeProp, &IllegalConv);
589 reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym, C);
597 if (OrigToDest && !DestToOrig)
598 std::swap(LowerBound, UpperBound);
601 LowerBound = LowerBound->
isObjCIdType() ? UpperBound : LowerBound;
602 UpperBound = UpperBound->
isObjCIdType() ? LowerBound : UpperBound;
606 C.addTransition(State, AfterTypeProp);
623 class IsObjCTypeParamDependentTypeVisitor
626 IsObjCTypeParamDependentTypeVisitor() : Result(
false) {}
628 if (isa<ObjCTypeParamDecl>(Type->
getDecl())) {
638 IsObjCTypeParamDependentTypeVisitor Visitor;
639 Visitor.TraverseType(Type);
640 return Visitor.Result;
654 const auto *ReceiverObjectPtrType =
704 void DynamicTypePropagation::checkPreObjCMessage(
const ObjCMethodCall &M,
705 CheckerContext &C)
const {
712 State->get<MostSpecializedTypeArgsMap>(Sym);
766 for (
unsigned i = 0; i < Method->
param_size(); i++) {
778 const auto *ArgObjectPtrType =
780 if (!ParamObjectPtrType || !ArgObjectPtrType)
785 SVal ArgSVal = M.getArgSVal(i);
786 SymbolRef ArgSym = ArgSVal.getAsSymbol();
789 State->get<MostSpecializedTypeArgsMap>(ArgSym);
790 if (TrackedArgType &&
792 ArgObjectPtrType = *TrackedArgType;
799 static CheckerProgramPointTag Tag(
this,
"ArgTypeMismatch");
800 ExplodedNode *N = C.addTransition(State, &Tag);
801 reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg);
814 void DynamicTypePropagation::checkPostObjCMessage(
const ObjCMethodCall &M,
815 CheckerContext &C)
const {
818 SymbolRef RetSym = M.getReturnValue().getAsSymbol();
831 if (!ReceiverClassType->isSpecialized())
835 C.getASTContext().getObjCObjectPointerType(
837 const auto *InferredType =
840 State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
841 C.addTransition(State);
851 State->get<MostSpecializedTypeArgsMap>(RecSym);
872 const MemRegion *RetRegion = M.getReturnValue().getAsRegion();
873 ExplodedNode *Pred = C.getPredecessor();
883 Pred = C.addTransition(State);
888 if (!ResultPtrType || ResultPtrType->isUnspecialized())
893 if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) {
894 State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType);
895 C.addTransition(State, Pred);
899 void DynamicTypePropagation::reportGenericsBug(
901 ExplodedNode *N,
SymbolRef Sym, CheckerContext &C,
902 const Stmt *ReportedNode)
const {
908 llvm::raw_svector_ostream
OS(Buf);
909 OS <<
"Conversion from value of type '";
911 OS <<
"' to incompatible type '";
914 auto R = std::make_unique<PathSensitiveBugReport>(*ObjCGenericsBugType,
916 R->markInteresting(Sym);
917 R->addVisitor(std::make_unique<GenericsBugVisitor>(Sym));
920 C.emitReport(std::move(R));
924 const ExplodedNode *N, BugReporterContext &BRC,
925 PathSensitiveBugReport &BR) {
930 state->get<MostSpecializedTypeArgsMap>(Sym);
932 statePrev->get<MostSpecializedTypeArgsMap>(Sym);
936 if (TrackedTypePrev && *TrackedTypePrev == *TrackedType)
940 const Stmt *S = N->getStmtForDiagnostics();
944 const LangOptions &LangOpts = BRC.getASTContext().getLangOpts();
947 llvm::raw_svector_ostream
OS(Buf);
950 OS <<
"' is inferred from ";
952 if (
const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
953 OS <<
"explicit cast (from '";
958 LangOpts, llvm::Twine());
960 }
else if (
const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
961 OS <<
"implicit cast (from '";
966 LangOpts, llvm::Twine());
969 OS <<
"this context";
973 PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
974 N->getLocationContext());
975 return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),
true);
979 void ento::registerObjCGenericsChecker(CheckerManager &mgr) {
980 DynamicTypePropagation *checker = mgr.getChecker<DynamicTypePropagation>();
981 checker->CheckGenerics =
true;
984 bool ento::shouldRegisterObjCGenericsChecker(
const LangOptions &LO) {
988 void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
989 mgr.registerChecker<DynamicTypePropagation>();
992 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()
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR, DynamicTypeInfo NewTy)
Set dynamic type information of the region; return the new state.
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.
const SymExpr * SymbolRef
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.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
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
ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR)
Removes the dead type informations from State.
This represents one expression.
static bool storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, const ObjCObjectPointerType *const *Current, const ObjCObjectPointerType *StaticLowerBound, const ObjCObjectPointerType *StaticUpperBound, ASTContext &C)
Inputs:
const T * castAs() const
Member-template castAs<specific type>.
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...
const DynamicTypeInfo * getRawDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR)
Get raw dynamic type information for the region MR.
bool isObjCClassType() const
DeclContext * getDeclContext()
bool isObjCIdType() const
True if this is equivalent to the 'id' type, i.e.
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.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
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.
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...
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR)
Get dynamic type information for the region MR.
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.
const ParentMap & getParentMap() const
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