]> granicus.if.org Git - clang/commitdiff
[analyzer] Invalidate union regions properly. Don't hesitate to load later.
authorArtem Dergachev <artem.dergachev@gmail.com>
Fri, 4 May 2018 22:19:32 +0000 (22:19 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Fri, 4 May 2018 22:19:32 +0000 (22:19 +0000)
We weren't invalidating our unions correctly. The previous behavior in
invalidateRegionsWorker::VisitCluster() was to direct-bind an UnknownVal
to the union (at offset 0).

For that reason we were never actually loading default bindings from our unions,
because there never was any default binding to load, and the value
that is presumed when there's no default binding to load
is usually completely incorrect (eg. UndefinedVal for stack unions).

The new behavior is to default-bind a conjured symbol (of irrelevant type)
to the union that's being invalidated, similarly to what we do for structures
and classes. Then it becomes safe to load the value properly.

Differential Revision: https://reviews.llvm.org/D45241

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

lib/StaticAnalyzer/Core/RegionStore.cpp
test/Analysis/unions.cpp

index d4624c089da70f3775a4f0721d08b7bd1319d02e..8f3205675d9dc8eaaec9d0130e545126309e47bf 100644 (file)
@@ -230,11 +230,6 @@ Optional<SVal> RegionBindingsRef::getDirectBinding(const MemRegion *R) const {
 }
 
 Optional<SVal> RegionBindingsRef::getDefaultBinding(const MemRegion *R) const {
-  if (R->isBoundable())
-    if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R))
-      if (TR->getValueType()->isUnionType())
-        return UnknownVal();
-
   return Optional<SVal>::create(lookup(R, BindingKey::Default));
 }
 
@@ -1099,7 +1094,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
     return;
   }
 
-  if (T->isStructureOrClassType()) {
+  if (T->isRecordType()) {
     // Invalidate the region by setting its default value to
     // conjured symbol. The type of the symbol is irrelevant.
     DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
index 2758cdaa26b3a71d78017398fc82b6b638263907..2d6d0ae4a0db330a4d528167402940fd8b48f673 100644 (file)
@@ -79,8 +79,7 @@ namespace PR17596 {
     IntOrString vv;
     vv.i = 5;
     uu = vv;
-    // FIXME: Should be true.
-    clang_analyzer_eval(uu.i == 5); // expected-warning{{UNKNOWN}}
+    clang_analyzer_eval(uu.i == 5); // expected-warning{{TRUE}}
   }
 
   void testInvalidation() {
@@ -106,3 +105,20 @@ namespace PR17596 {
     clang_analyzer_eval(uu.s[0] == 'a'); // expected-warning{{UNKNOWN}}
   }
 }
+
+namespace assume_union_contents {
+union U {
+  int x;
+};
+
+U get();
+
+void test() {
+  U u = get();
+  int y = 0;
+  if (u.x)
+    y = 1;
+  if (u.x)
+    y = 1 / y; // no-warning
+}
+} // end namespace assume_union_contents