diff options
author | Gabor Horvath <xazax.hun@gmail.com> | 2015-09-16 22:44:36 +0000 |
---|---|---|
committer | Gabor Horvath <xazax.hun@gmail.com> | 2015-09-16 22:44:36 +0000 |
commit | 3ef9ef222739470bc845b440aaee824ae981f427 (patch) | |
tree | b1b8594d5c943851d8bb1c5b633d9a17ad5ada49 /clang/lib/StaticAnalyzer/Checkers | |
parent | 813f1b65bc131b211ec5fef10ad47abc0488192d (diff) | |
download | bcm5719-llvm-3ef9ef222739470bc845b440aaee824ae981f427.tar.gz bcm5719-llvm-3ef9ef222739470bc845b440aaee824ae981f427.zip |
[Static Analyzer] Generics Checker: When an ObjC method returns a specialized object, track it properly.
Differential Revision: http://reviews.llvm.org/D12889
llvm-svn: 247861
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp | 212 |
1 files changed, 136 insertions, 76 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 9163db8584e..99b5353bd7d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -41,7 +41,10 @@ using namespace ento; // some cases the most derived type is not the most informative one about the // type parameters. This types that are stored for each symbol in this map must // be specialized. -REGISTER_MAP_WITH_PROGRAMSTATE(TypeParamMap, SymbolRef, +// TODO: In some case the type stored in this map is exactly the same that is +// stored in DynamicTypeMap. We should no store duplicated information in those +// cases. +REGISTER_MAP_WITH_PROGRAMSTATE(MostSpecializedTypeArgsMap, SymbolRef, const ObjCObjectPointerType *) namespace { @@ -96,11 +99,11 @@ class DynamicTypePropagation: SymbolRef Sym, CheckerContext &C, const Stmt *ReportedNode = nullptr) const; - void checkReturnType(const ObjCMessageExpr *MessageExpr, - const ObjCObjectPointerType *TrackedType, SymbolRef Sym, - const ObjCMethodDecl *Method, - ArrayRef<QualType> TypeArgs, bool SubscriptOrProperty, - CheckerContext &C) const; + bool isReturnValueMisused(const ObjCMessageExpr *MessageExpr, + const ObjCObjectPointerType *TrackedType, + SymbolRef Sym, const ObjCMethodDecl *Method, + ArrayRef<QualType> TypeArgs, + bool SubscriptOrProperty, CheckerContext &C) const; public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; @@ -132,11 +135,13 @@ void DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR, return; } - TypeParamMapTy TyParMap = State->get<TypeParamMap>(); - for (TypeParamMapTy::iterator I = TyParMap.begin(), E = TyParMap.end(); + MostSpecializedTypeArgsMapTy TyArgMap = + State->get<MostSpecializedTypeArgsMap>(); + for (MostSpecializedTypeArgsMapTy::iterator I = TyArgMap.begin(), + E = TyArgMap.end(); I != E; ++I) { if (SR.isDead(I->first)) { - State = State->remove<TypeParamMap>(I->first); + State = State->remove<MostSpecializedTypeArgsMap>(I->first); } } @@ -455,13 +460,13 @@ storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, // Case (1) if (!Current) { if (StaticUpperBound->isUnspecialized()) { - State = State->set<TypeParamMap>(Sym, StaticLowerBound); + State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound); return true; } // Upper bound is specialized. const ObjCObjectPointerType *WithMostInfo = getMostInformativeDerivedClass(StaticUpperBound, StaticLowerBound, C); - State = State->set<TypeParamMap>(Sym, WithMostInfo); + State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); return true; } @@ -479,7 +484,7 @@ storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, getMostInformativeDerivedClass(WithMostInfo, StaticLowerBound, C); if (WithMostInfo == *Current) return false; - State = State->set<TypeParamMap>(Sym, WithMostInfo); + State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); return true; } @@ -487,7 +492,7 @@ storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, const ObjCObjectPointerType *WithMostInfo = getMostInformativeDerivedClass(*Current, StaticLowerBound, C); if (WithMostInfo != *Current) { - State = State->set<TypeParamMap>(Sym, WithMostInfo); + State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); return true; } @@ -540,7 +545,7 @@ void DynamicTypePropagation::checkPostStmt(const CastExpr *CE, bool DestToOrig = ASTCtxt.canAssignObjCInterfaces(OrigObjectPtrType, DestObjectPtrType); const ObjCObjectPointerType *const *TrackedType = - State->get<TypeParamMap>(Sym); + State->get<MostSpecializedTypeArgsMap>(Sym); // Downcasts and upcasts handled in an uniform way regardless of being // explicit. Explicit casts however can happen between mismatched types. @@ -548,10 +553,10 @@ void DynamicTypePropagation::checkPostStmt(const CastExpr *CE, // Mismatched types. If the DestType specialized, store it. Forget the // tracked type otherwise. if (DestObjectPtrType->isSpecialized()) { - State = State->set<TypeParamMap>(Sym, DestObjectPtrType); + State = State->set<MostSpecializedTypeArgsMap>(Sym, DestObjectPtrType); C.addTransition(State, AfterTypeProp); } else if (TrackedType) { - State = State->remove<TypeParamMap>(Sym); + State = State->remove<MostSpecializedTypeArgsMap>(Sym); C.addTransition(State, AfterTypeProp); } return; @@ -596,41 +601,6 @@ static const Expr *stripCastsAndSugar(const Expr *E) { return E; } -/// This callback is used to infer the types for Class variables. This info is -/// used later to validate messages that sent to classes. Class variables are -/// initialized with by invoking the 'class' method on a class. -void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M, - CheckerContext &C) const { - const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); - - SymbolRef Sym = M.getReturnValue().getAsSymbol(); - if (!Sym) - return; - - Selector Sel = MessageExpr->getSelector(); - // We are only interested in cases where the class method is invoked on a - // class. This method is provided by the runtime and available on all classes. - if (MessageExpr->getReceiverKind() != ObjCMessageExpr::Class || - Sel.getAsString() != "class") - return; - - QualType ReceiverType = MessageExpr->getClassReceiver(); - const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>(); - QualType ReceiverClassPointerType = - C.getASTContext().getObjCObjectPointerType( - QualType(ReceiverClassType, 0)); - - if (!ReceiverClassType->isSpecialized()) - return; - const auto *InferredType = - ReceiverClassPointerType->getAs<ObjCObjectPointerType>(); - assert(InferredType); - - ProgramStateRef State = C.getState(); - State = State->set<TypeParamMap>(Sym, InferredType); - C.addTransition(State); -} - static bool isObjCTypeParamDependent(QualType Type) { // It is illegal to typedef parameterized types inside an interface. Therfore // an Objective-C type can only be dependent on a type parameter when the type @@ -692,24 +662,40 @@ findMethodDecl(const ObjCMessageExpr *MessageExpr, return Method ? Method : MessageExpr->getMethodDecl(); } +/// Get the returned ObjCObjectPointerType by a method based on the tracked type +/// information, or null pointer when the returned type is not an +/// ObjCObjectPointerType. +static const ObjCObjectPointerType *getReturnTypeForMethod( + const ObjCMethodDecl *Method, ArrayRef<QualType> TypeArgs, + const ObjCObjectPointerType *SelfType, ASTContext &C) { + QualType StaticResultType = Method->getReturnType(); + + // Is the return type declared as instance type? + if (StaticResultType == C.getObjCInstanceType()) + return SelfType; + + // Check whether the result type depends on a type parameter. + if (!isObjCTypeParamDependent(StaticResultType)) + return nullptr; + + QualType ResultType = StaticResultType.substObjCTypeArgs( + C, TypeArgs, ObjCSubstitutionContext::Result); + + return ResultType->getAs<ObjCObjectPointerType>(); +} + /// Validate that the return type of a message expression is used correctly. -void DynamicTypePropagation::checkReturnType( +/// Returns true in case an error is detected. +bool DynamicTypePropagation::isReturnValueMisused( const ObjCMessageExpr *MessageExpr, - const ObjCObjectPointerType *TrackedType, SymbolRef Sym, + const ObjCObjectPointerType *SeflType, SymbolRef Sym, const ObjCMethodDecl *Method, ArrayRef<QualType> TypeArgs, bool SubscriptOrProperty, CheckerContext &C) const { - QualType StaticResultType = Method->getReturnType(); ASTContext &ASTCtxt = C.getASTContext(); - // Check whether the result type was a type parameter. - bool IsDeclaredAsInstanceType = - StaticResultType == ASTCtxt.getObjCInstanceType(); - if (!isObjCTypeParamDependent(StaticResultType) && !IsDeclaredAsInstanceType) - return; - - QualType ResultType = Method->getReturnType().substObjCTypeArgs( - ASTCtxt, TypeArgs, ObjCSubstitutionContext::Result); - if (IsDeclaredAsInstanceType) - ResultType = QualType(TrackedType, 0); + const auto *ResultPtrType = + getReturnTypeForMethod(Method, TypeArgs, SeflType, ASTCtxt); + if (!ResultPtrType) + return false; const Stmt *Parent = C.getCurrentAnalysisDeclContext()->getParentMap().getParent(MessageExpr); @@ -721,14 +707,12 @@ void DynamicTypePropagation::checkReturnType( const auto *ImplicitCast = dyn_cast_or_null<ImplicitCastExpr>(Parent); if (!ImplicitCast || ImplicitCast->getCastKind() != CK_BitCast) - return; + return false; const auto *ExprTypeAboveCast = ImplicitCast->getType()->getAs<ObjCObjectPointerType>(); - const auto *ResultPtrType = ResultType->getAs<ObjCObjectPointerType>(); - - if (!ExprTypeAboveCast || !ResultPtrType) - return; + if (!ExprTypeAboveCast) + return false; // Only warn on unrelated types to avoid too many false positives on // downcasts. @@ -737,8 +721,9 @@ void DynamicTypePropagation::checkReturnType( static CheckerProgramPointTag Tag(this, "ReturnTypeMismatch"); ExplodedNode *N = C.addTransition(C.getState(), &Tag); reportGenericsBug(ResultPtrType, ExprTypeAboveCast, N, Sym, C); - return; + return true; } + return false; } /// When the receiver has a tracked type, use that type to validate the @@ -751,7 +736,7 @@ void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M, return; const ObjCObjectPointerType *const *TrackedType = - State->get<TypeParamMap>(Sym); + State->get<MostSpecializedTypeArgsMap>(Sym); if (!TrackedType) return; @@ -797,7 +782,7 @@ void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M, SymbolRef ArgSym = ArgSVal.getAsSymbol(); if (ArgSym) { const ObjCObjectPointerType *const *TrackedArgType = - State->get<TypeParamMap>(ArgSym); + State->get<MostSpecializedTypeArgsMap>(ArgSym); if (TrackedArgType && ASTCtxt.canAssignObjCInterfaces(ArgObjectPtrType, *TrackedArgType)) { ArgObjectPtrType = *TrackedArgType; @@ -813,9 +798,84 @@ void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M, return; } } +} + +/// This callback is used to infer the types for Class variables. This info is +/// used later to validate messages that sent to classes. Class variables are +/// initialized with by invoking the 'class' method on a class. +/// This method is also used to infer the type information for the return +/// types. +// TODO: right now it only tracks generic types. Extend this to track every +// type in the DynamicTypeMap and diagnose type errors! +void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M, + CheckerContext &C) const { + const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); + + SymbolRef RetSym = M.getReturnValue().getAsSymbol(); + if (!RetSym) + return; + + Selector Sel = MessageExpr->getSelector(); + ProgramStateRef State = C.getState(); + // Inference for class variables. + // We are only interested in cases where the class method is invoked on a + // class. This method is provided by the runtime and available on all classes. + if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Class && + Sel.getAsString() == "class") { + + QualType ReceiverType = MessageExpr->getClassReceiver(); + const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>(); + QualType ReceiverClassPointerType = + C.getASTContext().getObjCObjectPointerType( + QualType(ReceiverClassType, 0)); + + if (!ReceiverClassType->isSpecialized()) + return; + const auto *InferredType = + ReceiverClassPointerType->getAs<ObjCObjectPointerType>(); + assert(InferredType); + + State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType); + C.addTransition(State); + return; + } + + // Tracking for return types. + SymbolRef RecSym = M.getReceiverSVal().getAsSymbol(); + if (!RecSym) + return; + + const ObjCObjectPointerType *const *TrackedType = + State->get<MostSpecializedTypeArgsMap>(RecSym); + if (!TrackedType) + return; + + ASTContext &ASTCtxt = C.getASTContext(); + const ObjCMethodDecl *Method = + findMethodDecl(MessageExpr, *TrackedType, ASTCtxt); + if (!Method) + return; - checkReturnType(MessageExpr, *TrackedType, Sym, Method, *TypeArgs, - M.getMessageKind() != OCM_Message, C); + Optional<ArrayRef<QualType>> TypeArgs = + (*TrackedType)->getObjCSubstitutions(Method->getDeclContext()); + if (!TypeArgs) + return; + + if (isReturnValueMisused(MessageExpr, *TrackedType, RecSym, Method, *TypeArgs, + M.getMessageKind() != OCM_Message, C)) + return; + + const auto *ResultPtrType = + getReturnTypeForMethod(Method, *TypeArgs, *TrackedType, ASTCtxt); + if (!ResultPtrType || ResultPtrType->isUnspecialized()) + return; + + // When the result is a specialized type and it is not tracked yet, track it + // for the result symbol. + if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) { + State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType); + C.addTransition(State); + } } void DynamicTypePropagation::reportGenericsBug( @@ -849,9 +909,9 @@ PathDiagnosticPiece *DynamicTypePropagation::GenericsBugVisitor::VisitNode( ProgramStateRef statePrev = PrevN->getState(); const ObjCObjectPointerType *const *TrackedType = - state->get<TypeParamMap>(Sym); + state->get<MostSpecializedTypeArgsMap>(Sym); const ObjCObjectPointerType *const *TrackedTypePrev = - statePrev->get<TypeParamMap>(Sym); + statePrev->get<MostSpecializedTypeArgsMap>(Sym); if (!TrackedType) return nullptr; |