]> granicus.if.org Git - clang/commitdiff
[analyzer] Don't crash on implicit statements inside initializers.
authorJordan Rose <jordan_rose@apple.com>
Thu, 26 Jul 2012 20:04:30 +0000 (20:04 +0000)
committerJordan Rose <jordan_rose@apple.com>
Thu, 26 Jul 2012 20:04:30 +0000 (20:04 +0000)
Our BugReporter knows how to deal with implicit statements: it looks in
the ParentMap until it finds a parent with a valid location. However, since
initializers are not in the body of a constructor, their sub-expressions are
not in the ParentMap. That was easy enough to fix in AnalysisDeclContext.

...and then even once THAT was fixed, there's still an extra funny case
of Objective-C object pointer fields under ARC, which are initialized with
a top-level ImplicitValueInitExpr. To catch these cases,
PathDiagnosticLocation will now fall back to the start of the current
function if it can't find any other valid SourceLocations. This isn't great,
but it's miles better than a crash.

(All of this is only relevant when constructors and destructors are being
inlined, i.e. under -cfg-add-initializers and -cfg-add-implicit-dtors.)

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

lib/Analysis/AnalysisDeclContext.cpp
lib/StaticAnalyzer/Core/PathDiagnostic.cpp
test/Analysis/ctor-inlining.mm [new file with mode: 0644]
test/Analysis/dtor.cpp

index 32b1fcfe7c8b257de041cb1e4a7ab963ac266844..7de7f395e8a7f9900fd448925e4067f72b96e70c 100644 (file)
@@ -181,8 +181,16 @@ void AnalysisDeclContext::dumpCFG(bool ShowColors) {
 }
 
 ParentMap &AnalysisDeclContext::getParentMap() {
-  if (!PM)
+  if (!PM) {
     PM.reset(new ParentMap(getBody()));
+    if (const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(getDecl())) {
+      for (CXXConstructorDecl::init_const_iterator I = C->init_begin(),
+                                                   E = C->init_end();
+           I != E; ++I) {
+        PM->addStmt((*I)->getInit());
+      }
+    }
+  }
   return *PM;
 }
 
index 3306eaa7f88a8fa7e8e18bad788b79ca8854bd85..394e975d4e7ee36d8b2609cf48fdeea4958acb03 100644 (file)
@@ -253,16 +253,33 @@ static SourceLocation getValidSourceLocation(const Stmt* S,
   // source code, so find an enclosing statement and use its location.
   if (!L.isValid()) {
 
-    ParentMap *PM = 0;
+    AnalysisDeclContext *ADC;
     if (LAC.is<const LocationContext*>())
-      PM = &LAC.get<const LocationContext*>()->getParentMap();
+      ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
     else
-      PM = &LAC.get<AnalysisDeclContext*>()->getParentMap();
+      ADC = LAC.get<AnalysisDeclContext*>();
+
+    ParentMap &PM = ADC->getParentMap();
+
+    const Stmt *Parent = S;
+    do {
+      Parent = PM.getParent(Parent);
+
+      // In rare cases, we have implicit top-level expressions,
+      // such as arguments for implicit member initializers.
+      // In this case, fall back to the start of the body (even if we were
+      // asked for the statement end location).
+      if (!Parent) {
+        const Stmt *Body = ADC->getBody();
+        if (Body)
+          L = Body->getLocStart();
+        else
+          L = ADC->getDecl()->getLocEnd();
+        break;
+      }
 
-    while (!L.isValid()) {
-      S = PM->getParent(S);
-      L = UseEnd ? S->getLocEnd() : S->getLocStart();
-    }
+      L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
+    } while (!L.isValid());
   }
 
   return L;
diff --git a/test/Analysis/ctor-inlining.mm b/test/Analysis/ctor-inlining.mm
new file mode 100644 (file)
index 0000000..000e865
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -fobjc-arc -cfg-add-initializers -cfg-add-implicit-dtors -Wno-null-dereference -verify %s
+
+struct Wrapper {
+  __strong id obj;
+};
+
+void test() {
+  Wrapper w;
+  // force a diagnostic
+  *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
+}
index 4e3c0017f4a92efc0ef1197e1028d48d65ca328a..18884c5f9105733ead2db5a6284a332154421fcb 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -cfg-add-initializers -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -cfg-add-initializers -Wno-null-dereference -verify %s
 
 void clang_analyzer_eval(bool);
 
@@ -154,3 +154,22 @@ void testArrayInvalidation() {
   clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
   clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
 }
+
+
+
+// Don't crash on a default argument inside an initializer.
+struct DefaultArg {
+  DefaultArg(int x = 0) {}
+  ~DefaultArg();
+};
+
+struct InheritsDefaultArg : DefaultArg {
+  InheritsDefaultArg() {}
+  virtual ~InheritsDefaultArg();
+};
+
+void testDefaultArg() {
+  InheritsDefaultArg a;
+  // Force a bug to be emitted.
+  *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
+}