From 6f61df3e7256413dcb99afb9673f4206e3c4992c Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Fri, 28 Sep 2012 17:15:12 +0000 Subject: [PATCH] [analyzer] Create a temporary region for rvalue structs when accessing fields 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164828 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Core/ExprEngine.cpp | 18 +++++++++--------- test/Analysis/fields.c | 11 ++++++++++- test/Analysis/reference.cpp | 4 +--- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 8e2c159ca7..06216f83ea 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -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(baseExprVal) || - isa(baseExprVal) || - // FIXME: This can originate by conjuring a symbol for an unknown - // temporary struct object, see test/Analysis/fields.c: - // (p = getit()).x - isa(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(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; diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c index a10d5a8060..a2b3dcf738 100644 --- a/test/Analysis/fields.c +++ b/test/Analysis/fields.c @@ -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}} +} diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp index 374f3f7261..ce0ee8ed57 100644 --- a/test/Analysis/reference.cpp +++ b/test/Analysis/reference.cpp @@ -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 . 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}} -- 2.40.0