]> granicus.if.org Git - clang/commitdiff
Pull BadCallChecker int UndefinedArgChecker, and have UndefinedArgChecker also handle...
authorTed Kremenek <kremenek@apple.com>
Sat, 21 Nov 2009 01:25:37 +0000 (01:25 +0000)
committerTed Kremenek <kremenek@apple.com>
Sat, 21 Nov 2009 01:25:37 +0000 (01:25 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89524 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/PathSensitive/GRExprEngine.h
lib/Analysis/BadCallChecker.cpp [deleted file]
lib/Analysis/CMakeLists.txt
lib/Analysis/GRExprEngine.cpp
lib/Analysis/GRExprEngineInternalChecks.cpp
lib/Analysis/GRExprEngineInternalChecks.h
lib/Analysis/UndefinedArgChecker.cpp
test/Analysis/uninit-msg-expr.m
test/Analysis/uninit-ps-rdar6145427.m

index 75f04b6234652229b748f1b30cfbcf600d05e0a5..cca548ea4710e94dbe202c9ca0bac4ceeccafff8 100644 (file)
@@ -126,10 +126,6 @@ public:
   ///  by the result is not.  Excludes divide-by-zero errors.
   ErrorNodes UndefResults;
 
-  /// UndefReceiver - Nodes in the ExplodedGraph resulting from message
-  ///  ObjC message expressions where the receiver is undefined (uninitialized).
-  ErrorNodes UndefReceivers;
-
 public:
   GRExprEngine(AnalysisManager &mgr);
 
@@ -223,16 +219,6 @@ public:
   undef_result_iterator undef_results_begin() { return UndefResults.begin(); }
   undef_result_iterator undef_results_end() { return UndefResults.end(); }
 
-  typedef ErrorNodes::iterator undef_receivers_iterator;
-
-  undef_receivers_iterator undef_receivers_begin() {
-    return UndefReceivers.begin();
-  }
-
-  undef_receivers_iterator undef_receivers_end() {
-    return UndefReceivers.end();
-  }
-
   void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C);
   void AddCheck(GRSimpleAPICheck* A);
 
diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp
deleted file mode 100644 (file)
index 7a7ea18..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-//===--- BadCallChecker.h - Bad call checker --------------------*- C++ -*--==//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines BadCallChecker, a builtin check in GRExprEngine that performs
-// checks for bad callee at call sites.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "GRExprEngineInternalChecks.h"
-
-using namespace clang;
-
-namespace {
-class VISIBILITY_HIDDEN BadCallChecker : public CheckerVisitor<BadCallChecker> {
-  BuiltinBug *BT;
-public:
-  BadCallChecker() : BT(0) {}
-  static void *getTag() {
-    static int x = 0;
-    return &x;
-  }
-  void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-} // end anonymous namespace
-
-void clang::RegisterBadCallChecker(GRExprEngine &Eng) {
-  Eng.registerCheck(new BadCallChecker());
-}
-
-void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
-  const Expr *Callee = CE->getCallee()->IgnoreParens();
-  SVal L = C.getState()->getSVal(Callee);
-
-  if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
-    if (ExplodedNode *N = C.GenerateNode(CE, true)) {
-      if (!BT)
-        BT = new BuiltinBug("Invalid function call",
-                "Called function pointer is a null or undefined pointer value");
-
-      EnhancedBugReport *R =
-        new EnhancedBugReport(*BT, BT->getDescription(), N);
-        
-      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
-                           bugreporter::GetCalleeExpr(N));
-
-      C.EmitReport(R);
-    }
-  }
-}
index 8e8c1e7b25ed20e56323e2d0774dd6350dec4126..37852a0d7697fded378611a221e6077f2b8a1bbd 100644 (file)
@@ -4,7 +4,6 @@ add_clang_library(clangAnalysis
   AnalysisContext.cpp
   ArrayBoundChecker.cpp
   AttrNonNullChecker.cpp
-  BadCallChecker.cpp
   BasicConstraintManager.cpp
   BasicObjCFoundationChecks.cpp
   BasicStore.cpp
index 047e27dabdcd7d3049156181af9c9eb865bbc0e7..f5fe8d0371ca9a8f75a710596341ff87a85c6e1c 100644 (file)
@@ -1850,177 +1850,164 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
                                                       ExplodedNode* Pred,
                                                       ExplodedNodeSet& Dst) {
 
-  // FIXME: More logic for the processing the method call.
-
-  const GRState* state = GetState(Pred);
-  bool RaisesException = false;
-
+  // Handle previsits checks.
+  ExplodedNodeSet Src, DstTmp;
+  Src.Add(Pred);  
+  CheckerVisit(ME, DstTmp, Src, true);
+  
+  unsigned size = Dst.size();
 
-  if (Expr* Receiver = ME->getReceiver()) {
+  for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
+       DI!=DE; ++DI) {    
+    Pred = *DI;
+    // FIXME: More logic for the processing the method call.
+    const GRState* state = GetState(Pred);
+    bool RaisesException = false;
 
-    SVal L_untested = state->getSVal(Receiver);
+    if (Expr* Receiver = ME->getReceiver()) {
+      SVal L_untested = state->getSVal(Receiver);
 
-    // Check for undefined control-flow.
-    if (L_untested.isUndef()) {
-      ExplodedNode* N = Builder->generateNode(ME, state, Pred);
+      // "Assume" that the receiver is not NULL.
+      DefinedOrUnknownSVal L = cast<DefinedOrUnknownSVal>(L_untested);
+      const GRState *StNotNull = state->Assume(L, true);
 
-      if (N) {
-        N->markAsSink();
-        UndefReceivers.insert(N);
-      }
+      // "Assume" that the receiver is NULL.
+      const GRState *StNull = state->Assume(L, false);
 
-      return;
-    }
+      if (StNull) {
+        QualType RetTy = ME->getType();
 
-    // "Assume" that the receiver is not NULL.
-    DefinedOrUnknownSVal L = cast<DefinedOrUnknownSVal>(L_untested);
-    const GRState *StNotNull = state->Assume(L, true);
-
-    // "Assume" that the receiver is NULL.
-    const GRState *StNull = state->Assume(L, false);
-
-    if (StNull) {
-      QualType RetTy = ME->getType();
-
-      // Check if the receiver was nil and the return value a struct.
-      if (RetTy->isRecordType()) {
-        if (Pred->getParentMap().isConsumedExpr(ME)) {
-          // The [0 ...] expressions will return garbage.  Flag either an
-          // explicit or implicit error.  Because of the structure of this
-          // function we currently do not bifurfacte the state graph at
-          // this point.
-          // FIXME: We should bifurcate and fill the returned struct with
-          //  garbage.
-          if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
-            N->markAsSink();
-            if (StNotNull)
-              NilReceiverStructRetImplicit.insert(N);
-            else
-              NilReceiverStructRetExplicit.insert(N);
+        // Check if the receiver was nil and the return value a struct.
+        if (RetTy->isRecordType()) {
+          if (Pred->getParentMap().isConsumedExpr(ME)) {
+            // The [0 ...] expressions will return garbage.  Flag either an
+            // explicit or implicit error.  Because of the structure of this
+            // function we currently do not bifurfacte the state graph at
+            // this point.
+            // FIXME: We should bifurcate and fill the returned struct with
+            //  garbage.
+            if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
+              N->markAsSink();
+              if (StNotNull)
+                NilReceiverStructRetImplicit.insert(N);
+              else
+                NilReceiverStructRetExplicit.insert(N);
+            }
           }
         }
-      }
-      else {
-        ASTContext& Ctx = getContext();
-        if (RetTy != Ctx.VoidTy) {
-          if (Pred->getParentMap().isConsumedExpr(ME)) {
-            // sizeof(void *)
-            const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
-            // sizeof(return type)
-            const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType());
-
-            if (voidPtrSize < returnTypeSize) {
-              if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
-                N->markAsSink();
-                if (StNotNull)
-                  NilReceiverLargerThanVoidPtrRetImplicit.insert(N);
-                else
-                  NilReceiverLargerThanVoidPtrRetExplicit.insert(N);
+        else {
+          ASTContext& Ctx = getContext();
+          if (RetTy != Ctx.VoidTy) {
+            if (Pred->getParentMap().isConsumedExpr(ME)) {
+              // sizeof(void *)
+              const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
+              // sizeof(return type)
+              const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType());
+
+              if (voidPtrSize < returnTypeSize) {
+                if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
+                  N->markAsSink();
+                  if (StNotNull)
+                    NilReceiverLargerThanVoidPtrRetImplicit.insert(N);
+                  else
+                    NilReceiverLargerThanVoidPtrRetExplicit.insert(N);
+                }
+              }
+              else if (!StNotNull) {
+                // Handle the safe cases where the return value is 0 if the
+                // receiver is nil.
+                //
+                // FIXME: For now take the conservative approach that we only
+                // return null values if we *know* that the receiver is nil.
+                // This is because we can have surprises like:
+                //
+                //   ... = [[NSScreens screens] objectAtIndex:0];
+                //
+                // What can happen is that [... screens] could return nil, but
+                // it most likely isn't nil.  We should assume the semantics
+                // of this case unless we have *a lot* more knowledge.
+                //
+                SVal V = ValMgr.makeZeroVal(ME->getType());
+                MakeNode(Dst, ME, Pred, StNull->BindExpr(ME, V));
+                return;
               }
-            }
-            else if (!StNotNull) {
-              // Handle the safe cases where the return value is 0 if the
-              // receiver is nil.
-              //
-              // FIXME: For now take the conservative approach that we only
-              // return null values if we *know* that the receiver is nil.
-              // This is because we can have surprises like:
-              //
-              //   ... = [[NSScreens screens] objectAtIndex:0];
-              //
-              // What can happen is that [... screens] could return nil, but
-              // it most likely isn't nil.  We should assume the semantics
-              // of this case unless we have *a lot* more knowledge.
-              //
-              SVal V = ValMgr.makeZeroVal(ME->getType());
-              MakeNode(Dst, ME, Pred, StNull->BindExpr(ME, V));
-              return;
             }
           }
         }
+        // We have handled the cases where the receiver is nil.  The remainder
+        // of this method should assume that the receiver is not nil.
+        if (!StNotNull)
+          return;
+
+        state = StNotNull;
       }
-      // We have handled the cases where the receiver is nil.  The remainder
-      // of this method should assume that the receiver is not nil.
-      if (!StNotNull)
-        return;
 
-      state = StNotNull;
+      // Check if the "raise" message was sent.
+      if (ME->getSelector() == RaiseSel)
+        RaisesException = true;
     }
+    else {
 
-    // Check if the "raise" message was sent.
-    if (ME->getSelector() == RaiseSel)
-      RaisesException = true;
-  }
-  else {
+      IdentifierInfo* ClsName = ME->getClassName();
+      Selector S = ME->getSelector();
 
-    IdentifierInfo* ClsName = ME->getClassName();
-    Selector S = ME->getSelector();
+      // Check for special instance methods.
 
-    // Check for special instance methods.
+      if (!NSExceptionII) {
+        ASTContext& Ctx = getContext();
 
-    if (!NSExceptionII) {
-      ASTContext& Ctx = getContext();
+        NSExceptionII = &Ctx.Idents.get("NSException");
+      }
 
-      NSExceptionII = &Ctx.Idents.get("NSException");
-    }
+      if (ClsName == NSExceptionII) {
 
-    if (ClsName == NSExceptionII) {
+        enum { NUM_RAISE_SELECTORS = 2 };
 
-      enum { NUM_RAISE_SELECTORS = 2 };
+        // Lazily create a cache of the selectors.
 
-      // Lazily create a cache of the selectors.
+        if (!NSExceptionInstanceRaiseSelectors) {
 
-      if (!NSExceptionInstanceRaiseSelectors) {
+          ASTContext& Ctx = getContext();
 
-        ASTContext& Ctx = getContext();
+          NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
 
-        NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
+          llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
+          unsigned idx = 0;
 
-        llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
-        unsigned idx = 0;
+          // raise:format:
+          II.push_back(&Ctx.Idents.get("raise"));
+          II.push_back(&Ctx.Idents.get("format"));
+          NSExceptionInstanceRaiseSelectors[idx++] =
+            Ctx.Selectors.getSelector(II.size(), &II[0]);
 
-        // raise:format:
-        II.push_back(&Ctx.Idents.get("raise"));
-        II.push_back(&Ctx.Idents.get("format"));
-        NSExceptionInstanceRaiseSelectors[idx++] =
-          Ctx.Selectors.getSelector(II.size(), &II[0]);
+          // raise:format::arguments:
+          II.push_back(&Ctx.Idents.get("arguments"));
+          NSExceptionInstanceRaiseSelectors[idx++] =
+            Ctx.Selectors.getSelector(II.size(), &II[0]);
+        }
 
-        // raise:format::arguments:
-        II.push_back(&Ctx.Idents.get("arguments"));
-        NSExceptionInstanceRaiseSelectors[idx++] =
-          Ctx.Selectors.getSelector(II.size(), &II[0]);
+        for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
+          if (S == NSExceptionInstanceRaiseSelectors[i]) {
+            RaisesException = true; break;
+          }
       }
-
-      for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
-        if (S == NSExceptionInstanceRaiseSelectors[i]) {
-          RaisesException = true; break;
-        }
     }
-  }
 
-  // Handle previsits checks.
-  ExplodedNodeSet Src, DstTmp;
-  Src.Add(Pred);  
-  CheckerVisit(ME, DstTmp, Src, true);
-  
-  // Check if we raise an exception.  For now treat these as sinks.  Eventually
-  // we will want to handle exceptions properly.
-  SaveAndRestore<bool> OldSink(Builder->BuildSinks);
-  if (RaisesException)
-    Builder->BuildSinks = true;
+    // Check if we raise an exception.  For now treat these as sinks.  Eventually
+    // we will want to handle exceptions properly.
+    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+    if (RaisesException)
+      Builder->BuildSinks = true;
 
-  // Dispatch to plug-in transfer function.
-  unsigned size = Dst.size();
-  SaveOr OldHasGen(Builder->HasGeneratedNode);
-  
-  for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
-       DI!=DE; ++DI)
-    EvalObjCMessageExpr(Dst, ME, *DI);
+    // Dispatch to plug-in transfer function.
+    SaveOr OldHasGen(Builder->HasGeneratedNode);  
+    EvalObjCMessageExpr(Dst, ME, Pred);
+  }
 
   // Handle the case where no nodes where generated.  Auto-generate that
   // contains the updated state if we aren't generating sinks.
   if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
-    MakeNode(Dst, ME, Pred, state);
+    MakeNode(Dst, ME, Pred, GetState(Pred));
 }
 
 //===----------------------------------------------------------------------===//
index 50e855fda97e4efe4b0a05ccf02296c1d10e1491..8fcb3b7f48d90cb6f25c9250eadd745b12d7a47c 100644 (file)
@@ -219,34 +219,6 @@ public:
   const Stmt *getArg() const { return Arg; }
 };
 
-class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug {
-public:
-  BadReceiver(GRExprEngine* eng)
-  : BuiltinBug(eng,"Uninitialized receiver",
-               "Receiver in message expression is an uninitialized value") {}
-
-  void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
-    for (GRExprEngine::ErrorNodes::iterator I=Eng.undef_receivers_begin(),
-         End = Eng.undef_receivers_end(); I!=End; ++I) {
-
-      // Generate a report for this bug.
-      BuiltinBugReport *report = new BuiltinBugReport(*this, desc.c_str(), *I);
-      ExplodedNode* N = *I;
-      const Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
-      const Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
-      assert (E && "Receiver cannot be NULL");
-      report->addRange(E->getSourceRange());
-      BR.EmitReport(report);
-    }
-  }
-
-  void registerInitialVisitors(BugReporterContext& BRC,
-                               const ExplodedNode* N,
-                               BuiltinBugReport *R) {
-    registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
-  }
-};
-
 class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
   struct VISIBILITY_HIDDEN FindUndefExpr {
     GRStateManager& VM;
@@ -337,7 +309,6 @@ void GRExprEngine::RegisterInternalChecks() {
   // to 'FlushReports' from BugReporter.
   BR.Register(new UndefBranch(this));
   BR.Register(new UndefResult(this));
-  BR.Register(new BadReceiver(this));
   BR.Register(new NilReceiverStructRet(this));
   BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
 
@@ -350,7 +321,6 @@ void GRExprEngine::RegisterInternalChecks() {
   
   RegisterAttrNonNullChecker(*this);
   RegisterUndefinedArgChecker(*this);
-  RegisterBadCallChecker(*this);
   RegisterDereferenceChecker(*this);
   RegisterVLASizeChecker(*this);
   RegisterDivZeroChecker(*this);
index a9077bf75715bf3c5af24de0df0ff27169b72fbe..5db00132ef21daa3b68233abce5f5d2870c86eff 100644 (file)
@@ -20,7 +20,6 @@ namespace clang {
 class GRExprEngine;
 
 void RegisterAttrNonNullChecker(GRExprEngine &Eng);
-void RegisterBadCallChecker(GRExprEngine &Eng);
 void RegisterDereferenceChecker(GRExprEngine &Eng);
 void RegisterDivZeroChecker(GRExprEngine &Eng);
 void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
index a0c0d48712951cd40721932223481ddd98893c81..ea7d971fdb809cf0eabb6f93070485b92df33135 100644 (file)
@@ -21,16 +21,23 @@ using namespace clang;
 namespace {
 class VISIBILITY_HIDDEN UndefinedArgChecker
   : public CheckerVisitor<UndefinedArgChecker> {
-  BugType *BT_call;
-  BugType *BT_msg;
+  BugType *BT_call_null;
+  BugType *BT_call_undef;  
+  BugType *BT_call_arg;
+  BugType *BT_msg_undef;
+  BugType *BT_msg_arg;
 public:
-  UndefinedArgChecker() : BT_call(0), BT_msg(0) {}
+  UndefinedArgChecker() :
+    BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
+    BT_msg_undef(0), BT_msg_arg(0) {}
   static void *getTag() {
     static int x = 0;
     return &x;
   }
   void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
   void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+private:
+  void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
 };
 } // end anonymous namespace
 
@@ -38,18 +45,49 @@ void clang::RegisterUndefinedArgChecker(GRExprEngine &Eng) {
   Eng.registerCheck(new UndefinedArgChecker());
 }
 
+void UndefinedArgChecker::EmitBadCall(BugType *BT, CheckerContext &C,
+                                      const CallExpr *CE) {
+  ExplodedNode *N = C.GenerateNode(CE, true);
+  if (!N)
+    return;
+    
+  EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+  R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                       bugreporter::GetCalleeExpr(N));
+  C.EmitReport(R);
+}
+
 void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C, 
                                            const CallExpr *CE){
+  
+  const Expr *Callee = CE->getCallee()->IgnoreParens();
+  SVal L = C.getState()->getSVal(Callee);
+  
+  if (L.isUndef()) {
+    if (!BT_call_undef)
+      BT_call_undef =
+        new BuiltinBug("Called function pointer is an undefined pointer value");
+    EmitBadCall(BT_call_undef, C, CE);
+    return;
+  }
+  
+  if (isa<loc::ConcreteInt>(L)) {
+    if (!BT_call_null)
+      BT_call_null =
+        new BuiltinBug("Called function pointer is null (null dereference)");
+    EmitBadCall(BT_call_null, C, CE);
+  }  
+  
   for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
        I != E; ++I) {
     if (C.getState()->getSVal(*I).isUndef()) {
       if (ExplodedNode *N = C.GenerateNode(CE, true)) {
-        if (!BT_call)
-          BT_call = new BuiltinBug("Pass-by-value argument in function call is "
-                                   "undefined");
+        if (!BT_call_arg)
+          BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
+                                       " is undefined");
         // Generate a report for this bug.
-        EnhancedBugReport *R = new EnhancedBugReport(*BT_call,
-                                                     BT_call->getName(), N);
+        EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
+                                                     BT_call_arg->getName(), N);
         R->addRange((*I)->getSourceRange());
         R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
         C.EmitReport(R);
@@ -62,18 +100,36 @@ void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C,
 void UndefinedArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
                                                   const ObjCMessageExpr *ME) {
 
-  // Check for any arguments that are uninitialized/undefined.
   const GRState *state = C.getState();
+
+  if (const Expr *receiver = ME->getReceiver())
+    if (state->getSVal(receiver).isUndef()) {
+      if (ExplodedNode *N = C.GenerateNode(ME, true)) {
+        if (!BT_msg_undef)
+          BT_msg_undef =
+            new BuiltinBug("Receiver in message expression is a garbage value");
+        EnhancedBugReport *R =
+          new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
+        R->addRange(receiver->getSourceRange());
+        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                             receiver);
+        C.EmitReport(R);
+      }
+      return;
+    }
+
+  // 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.GenerateNode(ME, true)) {
-        if (!BT_msg)
-          BT_msg = new BuiltinBug("Pass-by-value argument in message expression"
-                                  " is undefined");      
+        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, BT_msg->getName(),
-                                                     N);
+        EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
+                                                     BT_msg_arg->getName(), N);
         R->addRange((*I)->getSourceRange());
         R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
         C.EmitReport(R);
index c2b73668dd959fca9f2487de9a26fc295f49c425..46e441f608d7fa038d5ca5eb2a820ffe24a95c7e 100644 (file)
@@ -42,7 +42,7 @@ extern NSString * const NSUndoManagerCheckpointNotification;
 
 unsigned f1() {
   NSString *aString;
-  return [aString length]; // expected-warning {{Receiver in message expression is an uninitialized value}}
+  return [aString length]; // expected-warning {{Receiver in message expression is a garbage value}}
 }
 
 unsigned f2() {
index d9e73188003f3ad62a62efba30bfbe4c7c558c46..7be32b4d157e2f6a62a486513eefb54bd26dcf51 100644 (file)
@@ -30,7 +30,7 @@ extern NSString * const NSUndoManagerCheckpointNotification;
 
 int main (int argc, const char * argv[]) {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-  id someUnintializedPointer = [someUnintializedPointer objectAtIndex:0]; // expected-warning{{Receiver in message expression is an uninitialized value.}}
+  id someUnintializedPointer = [someUnintializedPointer objectAtIndex:0]; // expected-warning{{Receiver in message expression is a garbage value}}
   NSLog(@"%@", someUnintializedPointer);    
   [pool drain];
   return 0;