]> granicus.if.org Git - clang/commitdiff
[analyzer] ObjC Inlining: Start tracking dynamic type info in the GDM
authorAnna Zaks <ganna@apple.com>
Fri, 3 Aug 2012 21:43:37 +0000 (21:43 +0000)
committerAnna Zaks <ganna@apple.com>
Fri, 3 Aug 2012 21:43:37 +0000 (21:43 +0000)
In the following code, find the type of the symbolic receiver by
following it and updating the dynamic type info in the state when we
cast the symbol from id to MyClass *.

  MyClass *a = [[self alloc] init];
  return 5/[a testSelf];

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161264 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
lib/StaticAnalyzer/Core/ExprEngineC.cpp
lib/StaticAnalyzer/Core/ProgramState.cpp
test/Analysis/inlining/InlineObjCInstanceMethod.m

index 4e92873860fcda811a27cfa87a9041c9dc17260b..9d82ec69837b4d64bcd421a1bbb386bcd12d8caa 100644 (file)
@@ -66,6 +66,12 @@ public:
   DynamicTypeInfo() : T(QualType()) {}
   DynamicTypeInfo(QualType WithType) : T(WithType) {}
   QualType getType() {return T;}
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    T.Profile(ID);
+  }
+  bool operator==(const DynamicTypeInfo &X) const {
+    return T == X.T;
+  }
 };
 
 /// \class ProgramState
@@ -327,6 +333,8 @@ public:
 
   /// Get dynamic type information for a region.
   DynamicTypeInfo getDynamicTypeInfo(const MemRegion *Reg) const;
+  /// Add dynamic type information to the region and return the new state.
+  ProgramStateRef addDynamicTypeInfo(const MemRegion *Reg, QualType NewTy)const;
 
   //==---------------------------------------------------------------------==//
   // Accessing the Generic Data Map (GDM).
index 7ec151ef6d7eae8904f6e86be8f9b18973779f8f..740dec5ec41556ab91e470de7938002d215407ea 100644 (file)
@@ -308,6 +308,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
         const LocationContext *LCtx = Pred->getLocationContext();
         SVal V = state->getSVal(Ex, LCtx);
         V = svalBuilder.evalCast(V, T, ExTy);
+        if (const MemRegion *R = V.getAsRegion()) {
+          state = state->addDynamicTypeInfo(R, T);
+        }
         state = state->BindExpr(CastE, LCtx, V);
         Bldr.generateNode(CastE, Pred, state);
         continue;
index 20f1e226b875f63cefdb2b8308a63d9d66fbebf7..5730bc985adc5152512a181808c13e2c05f98ddb 100644 (file)
@@ -732,11 +732,70 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
   return Tainted;
 }
 
+/// The GDM component containing the dynamic type info. This is a map from a
+/// symbol to it's most likely type.
+namespace clang {
+namespace ento {
+struct DynamicTypeMap {};
+typedef llvm::ImmutableMap<SymbolRef, DynamicTypeInfo> DynamicTypeMapImpl;
+template<> struct ProgramStateTrait<DynamicTypeMap>
+    :  public ProgramStatePartialTrait<DynamicTypeMapImpl> {
+  static void *GDMIndex() { static int index; return &index; }
+};
+}}
+
 DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const {
   if (const TypedRegion *TR = dyn_cast<TypedRegion>(Reg))
     return DynamicTypeInfo(TR->getLocationType());
-  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg))
-    return DynamicTypeInfo(SR->getSymbol()
-                             ->getType(getStateManager().getContext()));
+
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) {
+    SymbolRef Sym = SR->getSymbol();
+    // Lookup the dynamic type in the GDM.
+    const DynamicTypeInfo *GDMType = get<DynamicTypeMap>(Sym);
+    if (GDMType)
+      return *GDMType;
+
+    // Else, lookup the type at point of symbol creation.
+    return DynamicTypeInfo(Sym->getType(getStateManager().getContext()));
+  }
   return DynamicTypeInfo();
 }
+
+ProgramStateRef ProgramState::addDynamicTypeInfo(const MemRegion *Reg,
+                                                 QualType NewTy) const {
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) {
+    SymbolRef Sym = SR->getSymbol();
+    // TODO: Instead of resetting the type info, check the old type info and
+    // merge and pick the most precise type.
+    ProgramStateRef NewState = set<DynamicTypeMap>(Sym, DynamicTypeInfo(NewTy));
+    assert(NewState);
+    return NewState;
+  }
+  return this;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
index 8d8f28d923fec9bf36a04bab03f3166a17161d04..651d7c5b5a288c8b7822d4ab06b61e260939e38c 100644 (file)
   return 5/y; // expected-warning {{Division by zero}}
 }
 
-// Method is called on inited object.
+// Get the dynamic type info from a cast (from id to MyClass*).
 + (int)testAllocInit {
   MyClass *a = [[self alloc] init];
-  return 5/[a getInt]; // todo
+  return 5/[a getInt]; // expected-warning {{Division by zero}}
 }
 
 // Method is called on inited object.