[cfe-commits] r98800 - in /cfe/trunk: lib/Checker/CallAndMessageChecker.cpp test/Analysis/uninit-vals-ps-region.c test/Analysis/uninit-vals-ps-region.m

Ted Kremenek kremenek at apple.com
Wed Mar 17 20:22:29 PDT 2010


Author: kremenek
Date: Wed Mar 17 22:22:29 2010
New Revision: 98800

URL: http://llvm.org/viewvc/llvm-project?rev=98800&view=rev
Log:
Refactor argument checking in CallAndMessageChecker to be the same
for both CallExprs and ObjCMessageExprs.

Added:
    cfe/trunk/test/Analysis/uninit-vals-ps-region.m
      - copied, changed from r98799, cfe/trunk/test/Analysis/uninit-vals-ps-region.c
Removed:
    cfe/trunk/test/Analysis/uninit-vals-ps-region.c
Modified:
    cfe/trunk/lib/Checker/CallAndMessageChecker.cpp

Modified: cfe/trunk/lib/Checker/CallAndMessageChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallAndMessageChecker.cpp?rev=98800&r1=98799&r2=98800&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/CallAndMessageChecker.cpp (original)
+++ cfe/trunk/lib/Checker/CallAndMessageChecker.cpp Wed Mar 17 22:22:29 2010
@@ -44,6 +44,9 @@
   bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
 
 private:
+  bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
+                          const char *BT_desc, BugType *&BT);
+
   void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
   void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
                           ExplodedNode *N);
@@ -51,10 +54,9 @@
   void HandleNilReceiver(CheckerContext &C, const GRState *state,
                          const ObjCMessageExpr *ME);
 
-  void LazyInit_BT_call_arg() {
-    if (!BT_call_arg)
-      BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
-                                   " is undefined");
+  void LazyInit_BT(const char *desc, BugType *&BT) {
+    if (!BT)
+      BT = new BuiltinBug(desc);
   }
 };
 } // end anonymous namespace
@@ -75,6 +77,114 @@
   C.EmitReport(R);
 }
 
+bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
+                                               const Expr *Ex,
+                                               const char *BT_desc,
+                                               BugType *&BT) {
+
+  const SVal &V = C.getState()->getSVal(Ex);
+
+  if (V.isUndef()) {
+    if (ExplodedNode *N = C.GenerateSink()) {
+      LazyInit_BT(BT_desc, BT);
+
+      // Generate a report for this bug.
+      EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+      R->addRange(Ex->getSourceRange());
+      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+      C.EmitReport(R);
+    }
+    return true;
+  }
+
+  if (const nonloc::LazyCompoundVal *LV =
+        dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+    class FindUninitializedField {
+    public:
+      llvm::SmallVector<const FieldDecl *, 10> FieldChain;
+    private:
+      ASTContext &C;
+      StoreManager &StoreMgr;
+      MemRegionManager &MrMgr;
+      Store store;
+    public:
+      FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
+                             MemRegionManager &mrMgr, Store s)
+      : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
+
+      bool Find(const TypedRegion *R) {
+        QualType T = R->getValueType(C);
+        if (const RecordType *RT = T->getAsStructureType()) {
+          const RecordDecl *RD = RT->getDecl()->getDefinition();
+          assert(RD && "Referred record has no definition");
+          for (RecordDecl::field_iterator I =
+               RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
+            const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
+            FieldChain.push_back(*I);
+            T = (*I)->getType();
+            if (T->getAsStructureType()) {
+              if (Find(FR))
+                return true;
+            }
+            else {
+              const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
+              if (V.isUndef())
+                return true;
+            }
+            FieldChain.pop_back();
+          }
+        }
+
+        return false;
+      }
+    };
+
+    const LazyCompoundValData *D = LV->getCVData();
+    FindUninitializedField F(C.getASTContext(),
+                             C.getState()->getStateManager().getStoreManager(),
+                             C.getValueManager().getRegionManager(),
+                             D->getStore());
+
+    if (F.Find(D->getRegion())) {
+      if (ExplodedNode *N = C.GenerateSink()) {
+        LazyInit_BT(BT_desc, BT);
+        llvm::SmallString<512> Str;
+        llvm::raw_svector_ostream os(Str);
+        os << "Passed-by-value struct argument contains uninitialized data";
+
+        if (F.FieldChain.size() == 1)
+          os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString()
+             << "')";
+        else {
+          os << " (e.g., via the field chain: '";
+          bool first = true;
+          for (llvm::SmallVectorImpl<const FieldDecl *>::iterator
+               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
+            if (first)
+              first = false;
+            else
+              os << '.';
+            os << (*DI)->getNameAsString();
+          }
+          os << "')";
+        }
+
+        // Generate a report for this bug.
+        EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
+        R->addRange(Ex->getSourceRange());
+
+        // FIXME: enhance track back for uninitialized value for arbitrary
+        // memregions
+        C.EmitReport(R);
+      }
+      return true;
+    }
+  }
+
+  return false;
+}
+
 void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
                                              const CallExpr *CE){
 
@@ -97,105 +207,11 @@
   }
 
   for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
-       I != E; ++I) {
-    const SVal &V = C.getState()->getSVal(*I);
-    if (V.isUndef()) {
-      if (ExplodedNode *N = C.GenerateSink()) {
-        LazyInit_BT_call_arg();
-
-        // Generate a report for this bug.
-        EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
-                                                     BT_call_arg->getName(), N);
-        R->addRange((*I)->getSourceRange());
-        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
-        C.EmitReport(R);
-        return;
-      }
-    }
-    if (const nonloc::LazyCompoundVal *LV =
-          dyn_cast<nonloc::LazyCompoundVal>(&V)) {
-      const LazyCompoundValData *D = LV->getCVData();
-
-      class FindUninitializedField {
-      public:
-        llvm::SmallVector<const FieldDecl *, 10> FieldChain;
-      private:
-        ASTContext &C;
-        StoreManager &StoreMgr;
-        MemRegionManager &MrMgr;
-        Store store;
-      public:
-        FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
-                               MemRegionManager &mrMgr, Store s)
-          : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
-
-        bool Find(const TypedRegion *R) {
-          QualType T = R->getValueType(C);
-          if (const RecordType *RT = T->getAsStructureType()) {
-            const RecordDecl *RD = RT->getDecl()->getDefinition();
-            assert(RD && "Referred record has no definition");
-            for (RecordDecl::field_iterator I =
-                  RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
-              const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
-              FieldChain.push_back(*I);
-              T = (*I)->getType();
-              if (T->getAsStructureType()) {
-                if (Find(FR))
-                  return true;
-              }
-              else {
-                const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
-                if (V.isUndef())
-                  return true;
-              }
-              FieldChain.pop_back();
-            }
-          }
-
-          return false;
-        }
-      };
-
-      FindUninitializedField F(C.getASTContext(),
-                               C.getState()->getStateManager().getStoreManager(),
-                               C.getValueManager().getRegionManager(),
-                               D->getStore());
-
-      if (F.Find(D->getRegion())) {
-        if (ExplodedNode *N = C.GenerateSink()) {
-          LazyInit_BT_call_arg();
-          llvm::SmallString<512> Str;
-          llvm::raw_svector_ostream os(Str);
-          os << "Passed-by-value struct argument contains uninitialized data";
-
-          if (F.FieldChain.size() == 1)
-            os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString() << "')";
-          else {
-            os << " (e.g., via the field chain: '";
-            bool first = true;
-            for (llvm::SmallVectorImpl<const FieldDecl *>::iterator
-                 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
-              if (first)
-                first = false;
-              else
-                os << '.';
-              os << (*DI)->getNameAsString();
-            }
-            os << "')";
-          }
-
-          // Generate a report for this bug.
-          EnhancedBugReport *R =
-            new EnhancedBugReport(*BT_call_arg, os.str(), N);
-          R->addRange((*I)->getSourceRange());
-
-          // FIXME: enhance track back for uninitialized value for arbitrary
-          // memregions
-          C.EmitReport(R);
-        }
-      }
-    }
-  }
+       I != E; ++I)
+    if (PreVisitProcessArg(C, *I,
+                           "Pass-by-value argument in function call is"
+                           " undefined", BT_call_arg))
+      return;
 }
 
 void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
@@ -221,23 +237,11 @@
 
   // Check for any arguments that are uninitialized/undefined.
   for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
-         E = ME->arg_end(); I != E; ++I) {
-    if (state->getSVal(*I).isUndef()) {
-      if (ExplodedNode *N = C.GenerateSink()) {
-        if (!BT_msg_arg)
-          BT_msg_arg =
-            new BuiltinBug("Pass-by-value argument in message expression"
-                           " is undefined");
-        // Generate a report for this bug.
-        EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
-                                                     BT_msg_arg->getName(), N);
-        R->addRange((*I)->getSourceRange());
-        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
-        C.EmitReport(R);
+         E = ME->arg_end(); I != E; ++I)
+    if (PreVisitProcessArg(C, *I,
+                           "Pass-by-value argument in message expression "
+                           "is undefined", BT_msg_arg))
         return;
-      }
-    }
-  }
 }
 
 bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,

Removed: cfe/trunk/test/Analysis/uninit-vals-ps-region.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/uninit-vals-ps-region.c?rev=98799&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/uninit-vals-ps-region.c (original)
+++ cfe/trunk/test/Analysis/uninit-vals-ps-region.c (removed)
@@ -1,53 +0,0 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
-
-struct s {
-  int data;
-};
-
-struct s global;
-
-void g(int);
-
-void f4() {
-  int a;
-  if (global.data == 0)
-    a = 3;
-  if (global.data == 0) // When the true branch is feasible 'a = 3'.
-    g(a); // no-warning
-}
-
-
-// Test uninitialized value due to part of the structure being uninitialized.
-struct TestUninit { int x; int y; };
-struct TestUninit test_uninit_aux();
-void test_unit_aux2(int);
-void test_uninit_pos() {
-  struct TestUninit v1 = { 0, 0 };
-  struct TestUninit v2 = test_uninit_aux();
-  int z;
-  v1.y = z; // expected-warning{{Assigned value is garbage or undefined}}
-  test_unit_aux2(v2.x + v1.y);
-}
-void test_uninit_pos_2() {
-  struct TestUninit v1 = { 0, 0 };
-  struct TestUninit v2;
-  test_unit_aux2(v2.x + v1.y);  // expected-warning{{The left operand of '+' is a garbage value}}
-}
-void test_uninit_pos_3() {
-  struct TestUninit v1 = { 0, 0 };
-  struct TestUninit v2;
-  test_unit_aux2(v1.y + v2.x);  // expected-warning{{The right operand of '+' is a garbage value}}
-}
-
-void test_uninit_neg() {
-  struct TestUninit v1 = { 0, 0 };
-  struct TestUninit v2 = test_uninit_aux();
-  test_unit_aux2(v2.x + v1.y); // no-warning
-}
-
-extern void test_uninit_struct_arg_aux(struct TestUninit arg);
-void test_uninit_struct_arg() {
-  struct TestUninit x;
-  test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
-}
-

Copied: cfe/trunk/test/Analysis/uninit-vals-ps-region.m (from r98799, cfe/trunk/test/Analysis/uninit-vals-ps-region.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/uninit-vals-ps-region.m?p2=cfe/trunk/test/Analysis/uninit-vals-ps-region.m&p1=cfe/trunk/test/Analysis/uninit-vals-ps-region.c&r1=98799&r2=98800&rev=98800&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/uninit-vals-ps-region.c (original)
+++ cfe/trunk/test/Analysis/uninit-vals-ps-region.m Wed Mar 17 22:22:29 2010
@@ -51,3 +51,12 @@
   test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
 }
 
+ at interface Foo
+- (void) passVal:(struct TestUninit)arg;
+ at end
+void testFoo(Foo *o) {
+  struct TestUninit x;
+  [o passVal:x]; // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
+}
+
+





More information about the cfe-commits mailing list