NoQ created this revision.

In `ProgramState::getSVal(Loc, QualType)`, the `QualType` parameter, which 
represents the type of the expected value, is optional. If it is not supplied, 
it is auto-detected by looking at the memory region in `Loc`. For typed-value 
regions such autodetection is trivial. For other kinds of regions (most 
importantly, for symbolic regions) it apparently never worked correctly: it 
detected the location type (pointer type), not the value type in this location 
(pointee type).

Our tests contain numerous cases when such autodetection was working 
incorrectly, but for existing tests it never mattered. There are three notable 
places where the type was regularly auto-detected incorrectly:

1. `ExprEngine::performTrivialCopy()`. Trivial copy from symbolic references 
never worked - test case attached.
2. `CallAndMessageChecker::uninitRefOrPointer()`. Here the code only cares if 
the value is `Undefined` or not, so autodetected type didn't matter.
3. `GTestChecker::modelAssertionResultBoolConstructor()`. This is how the issue 
was found in https://bugs.llvm.org/show_bug.cgi?id=34305 - test case attached.

I added a few more sanity checks - we'd now also fail with an assertion if we 
are unable to autodetect the pointer type, warning the author of the checker to 
pass the type explicitly.

It is sometimes indeed handy to put a void-pointer-typed `Loc` into 
`getSVal(Loc)`, as demonstrated in the `exercise-ps.c`'s `f2()` test through 
`CallAndMessageChecker` (case '2.' above). I handled this on the API side in 
order to simplify checker API, implicitly turning `void` into `char`, though i 
don't mind modifying `CallAndMessageChecker` to pass `CharTy` explicitly 
instead.


https://reviews.llvm.org/D38358

Files:
  lib/StaticAnalyzer/Core/RegionStore.cpp
  test/Analysis/ctor.mm
  test/Analysis/gtest.cpp


Index: test/Analysis/gtest.cpp
===================================================================
--- test/Analysis/gtest.cpp
+++ test/Analysis/gtest.cpp
@@ -151,3 +151,9 @@
   ASSERT_TRUE(false);
   clang_analyzer_warnIfReached(); // no-warning
 }
+
+void testAssertSymbolic(const bool &b) {
+  ASSERT_TRUE(b);
+
+  clang_analyzer_eval(b); // expected-warning{{UNKNOWN}}
+}
Index: test/Analysis/ctor.mm
===================================================================
--- test/Analysis/ctor.mm
+++ test/Analysis/ctor.mm
@@ -199,7 +199,7 @@
     Inner p;
   };
 
-  void testPOD() {
+  void testPOD(const POD &pp) {
     POD p;
     p.x = 1;
     POD p2 = p; // no-warning
@@ -210,6 +210,15 @@
     // Use rvalues as well.
     clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
 
+    // Copy from symbolic references correctly.
+    POD p4 = pp;
+    // Make sure that p4.x contains a symbol after copy.
+    if (p4.x > 0)
+      clang_analyzer_eval(p4.x > 0); // expected-warning{{TRUE}}
+    // FIXME: Element region gets in the way, so these aren't the same symbols
+    // as they should be.
+    clang_analyzer_eval(pp.x == p4.x); // expected-warning{{UNKNOWN}}
+
     PODWrapper w;
     w.p.y = 1;
     PODWrapper w2 = w; // no-warning
Index: lib/StaticAnalyzer/Core/RegionStore.cpp
===================================================================
--- lib/StaticAnalyzer/Core/RegionStore.cpp
+++ lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1393,17 +1393,20 @@
     return UnknownVal();
   }
 
-  if (isa<AllocaRegion>(MR) ||
-      isa<SymbolicRegion>(MR) ||
-      isa<CodeTextRegion>(MR)) {
+  if (!isa<TypedValueRegion>(MR)) {
     if (T.isNull()) {
-      if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR))
-        T = TR->getLocationType();
-      else {
-        const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
-        T = SR->getSymbol()->getType();
+      if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR)) {
+        T = TR->getLocationType()->getPointeeType();
+      } else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) {
+        T = SR->getSymbol()->getType()->getPointeeType();
+        if (T->isVoidType()) {
+          // When trying to dereference a void pointer, read the first byte.
+          T = Ctx.CharTy;
+        }
       }
     }
+    assert(!T.isNull() && "Unable to auto-detect binding type!");
+    assert(!T->isVoidType() && "Attempted to retrieve a void value!");
     MR = GetElementZeroRegion(cast<SubRegion>(MR), T);
   }
 


Index: test/Analysis/gtest.cpp
===================================================================
--- test/Analysis/gtest.cpp
+++ test/Analysis/gtest.cpp
@@ -151,3 +151,9 @@
   ASSERT_TRUE(false);
   clang_analyzer_warnIfReached(); // no-warning
 }
+
+void testAssertSymbolic(const bool &b) {
+  ASSERT_TRUE(b);
+
+  clang_analyzer_eval(b); // expected-warning{{UNKNOWN}}
+}
Index: test/Analysis/ctor.mm
===================================================================
--- test/Analysis/ctor.mm
+++ test/Analysis/ctor.mm
@@ -199,7 +199,7 @@
     Inner p;
   };
 
-  void testPOD() {
+  void testPOD(const POD &pp) {
     POD p;
     p.x = 1;
     POD p2 = p; // no-warning
@@ -210,6 +210,15 @@
     // Use rvalues as well.
     clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
 
+    // Copy from symbolic references correctly.
+    POD p4 = pp;
+    // Make sure that p4.x contains a symbol after copy.
+    if (p4.x > 0)
+      clang_analyzer_eval(p4.x > 0); // expected-warning{{TRUE}}
+    // FIXME: Element region gets in the way, so these aren't the same symbols
+    // as they should be.
+    clang_analyzer_eval(pp.x == p4.x); // expected-warning{{UNKNOWN}}
+
     PODWrapper w;
     w.p.y = 1;
     PODWrapper w2 = w; // no-warning
Index: lib/StaticAnalyzer/Core/RegionStore.cpp
===================================================================
--- lib/StaticAnalyzer/Core/RegionStore.cpp
+++ lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1393,17 +1393,20 @@
     return UnknownVal();
   }
 
-  if (isa<AllocaRegion>(MR) ||
-      isa<SymbolicRegion>(MR) ||
-      isa<CodeTextRegion>(MR)) {
+  if (!isa<TypedValueRegion>(MR)) {
     if (T.isNull()) {
-      if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR))
-        T = TR->getLocationType();
-      else {
-        const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
-        T = SR->getSymbol()->getType();
+      if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR)) {
+        T = TR->getLocationType()->getPointeeType();
+      } else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) {
+        T = SR->getSymbol()->getType()->getPointeeType();
+        if (T->isVoidType()) {
+          // When trying to dereference a void pointer, read the first byte.
+          T = Ctx.CharTy;
+        }
       }
     }
+    assert(!T.isNull() && "Unable to auto-detect binding type!");
+    assert(!T->isVoidType() && "Attempted to retrieve a void value!");
     MR = GetElementZeroRegion(cast<SubRegion>(MR), T);
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to