]> granicus.if.org Git - clang/commitdiff
[analyzer] Create a temporary region for rvalue structs when accessing fields
authorJordan Rose <jordan_rose@apple.com>
Fri, 28 Sep 2012 17:15:12 +0000 (17:15 +0000)
committerJordan Rose <jordan_rose@apple.com>
Fri, 28 Sep 2012 17:15:12 +0000 (17:15 +0000)
Struct rvalues are represented in the analyzer by CompoundVals,
LazyCompoundVals, or plain ConjuredSymbols -- none of which have associated
regions. If the entire structure is going to persist, this is not a
problem -- either the rvalue will be assigned to an existing region, or
a MaterializeTemporaryExpr will be present to create a temporary region.
However, if we just need a field from the struct, we need to create the
temporary region ourselves.

This is inspired by the way CodeGen handles calls to temporaries;
support for that in the analyzer is coming next.

Part of <rdar://problem/12137950>

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

lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/fields.c
test/Analysis/reference.cpp

index 8e2c159ca7d71f46cf6836ef4c1311fa3c14ec5c..06216f83ea90241d55d749b9ea64faf3c288ce86 100644 (file)
@@ -1505,17 +1505,17 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
   ProgramStateRef state = Pred->getState();
   const LocationContext *LCtx = Pred->getLocationContext();
   SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext());
-  if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
-      isa<nonloc::CompoundVal>(baseExprVal) ||
-      // FIXME: This can originate by conjuring a symbol for an unknown
-      // temporary struct object, see test/Analysis/fields.c:
-      // (p = getit()).x
-      isa<nonloc::SymbolVal>(baseExprVal)) {
-    Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, UnknownVal()));
-    return;
+
+  // If we're accessing a field of an rvalue, we need to treat it like a
+  // temporary object.
+  if (isa<NonLoc>(baseExprVal)) {
+    const MemRegion *R  =
+      svalBuilder.getRegionManager().getCXXTempObjectRegion(baseExpr, LCtx);
+    SVal L = loc::MemRegionVal(R);
+    state = state->bindLoc(L, baseExprVal);
+    baseExprVal = L;
   }
 
-  // For all other cases, compute an lvalue.    
   SVal L = state->getLValue(field, baseExprVal);
   if (M->isGLValue()) {
     ExplodedNodeSet Tmp;
index a10d5a806016d7b1b915711f7e1f1a7f185a1d8b..a2b3dcf7384b21950a4dc260c5f27e9b30e6f67a 100644 (file)
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection %s -analyzer-store=region -verify
+
+void clang_analyzer_eval(int);
 
 unsigned foo();
 typedef struct bf { unsigned x:2; } bf;
@@ -33,3 +35,10 @@ void testNullAddress() {
   int *px = &p->x; // expected-warning{{Access to field 'x' results in a dereference of a null pointer (loaded from variable 'p')}}
   *px = 1; // No warning because analysis stops at the previous line.
 }
+
+void testLazyCompoundVal() {
+  Point p = {42, 0};
+  Point q;
+  clang_analyzer_eval((q = p).x == 42); // expected-warning{{TRUE}}
+  clang_analyzer_eval(q.x == 42); // expected-warning{{TRUE}}
+}
index 374f3f7261c76f47fe716e209a91c60872931043..ce0ee8ed57d07139335319c299e0f927e8cec154 100644 (file)
@@ -116,10 +116,8 @@ void testReferenceAddress(int &x) {
 
   struct S { int &x; };
 
-  // FIXME: Should be TRUE. Fields of return-by-value structs are not yet
-  // symbolicated. Tracked by <rdar://problem/12137950>.
   extern S getS();
-  clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(&getS().x != 0); // expected-warning{{TRUE}}
 
   extern S *getSP();
   clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}}