summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers
diff options
context:
space:
mode:
authorGabor Horvath <xazax.hun@gmail.com>2015-09-16 22:44:36 +0000
committerGabor Horvath <xazax.hun@gmail.com>2015-09-16 22:44:36 +0000
commit3ef9ef222739470bc845b440aaee824ae981f427 (patch)
treeb1b8594d5c943851d8bb1c5b633d9a17ad5ada49 /clang/lib/StaticAnalyzer/Checkers
parent813f1b65bc131b211ec5fef10ad47abc0488192d (diff)
downloadbcm5719-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.cpp212
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;
OpenPOWER on IntegriCloud