From: Jordan Rose Date: Fri, 28 Sep 2012 17:15:21 +0000 (+0000) Subject: [analyzer] Create a temp region when a method is called on a struct rvalue. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b559f185842eef73066382adcdfda9255608ad6f;p=platform%2Fupstream%2Fllvm.git [analyzer] Create a temp region when a method is called on a struct rvalue. An rvalue has no address, but calling a C++ member function requires a 'this' pointer. This commit makes the analyzer create a temporary region in which to store the struct rvalue and use as a 'this' pointer whenever a member function is called on an rvalue, which is essentially what CodeGen does. More of . The last part is tracking down the C++ FIXME in array-struct-region.cpp. llvm-svn: 164829 --- diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 06216f8..3965f04 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1470,6 +1470,23 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, } } +/// If the value of the given expression is a NonLoc, copy it into a new +/// temporary region, and replace the value of the expression with that. +static ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State, + const LocationContext *LC, + const Expr *E) { + SVal V = State->getSVal(E, LC); + + if (isa(V)) { + MemRegionManager &MRMgr = State->getStateManager().getRegionManager(); + const MemRegion *R = MRMgr.getCXXTempObjectRegion(E, LC); + State = State->bindLoc(loc::MemRegionVal(R), V); + State = State->BindExpr(E, LC, loc::MemRegionVal(R)); + } + + return State; +} + /// VisitMemberExpr - Transfer function for member expressions. void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, ExplodedNodeSet &TopDst) { @@ -1478,6 +1495,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, ExplodedNodeSet Dst; Decl *member = M->getMemberDecl(); + // Handle static member variables accessed via member syntax. if (VarDecl *VD = dyn_cast(member)) { assert(M->isGLValue()); Bldr.takeNodes(Pred); @@ -1486,36 +1504,27 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, return; } + ProgramStateRef state = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + Expr *BaseExpr = M->getBase()->IgnoreParens(); + // Handle C++ method calls. if (const CXXMethodDecl *MD = dyn_cast(member)) { - Bldr.takeNodes(Pred); + if (MD->isInstance()) + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + SVal MDVal = svalBuilder.getFunctionPointer(MD); - ProgramStateRef state = - Pred->getState()->BindExpr(M, Pred->getLocationContext(), MDVal); + state = state->BindExpr(M, LCtx, MDVal); + Bldr.generateNode(M, Pred, state); return; } + // Handle regular struct fields / member variables. + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + SVal baseExprVal = state->getSVal(BaseExpr, LCtx); - FieldDecl *field = dyn_cast(member); - if (!field) // FIXME: skipping member expressions for non-fields - return; - - Expr *baseExpr = M->getBase()->IgnoreParens(); - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); - SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext()); - - // 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; - } - + FieldDecl *field = cast(member); SVal L = state->getLValue(field, baseExprVal); if (M->isGLValue()) { ExplodedNodeSet Tmp; diff --git a/clang/test/Analysis/array-struct-region.cpp b/clang/test/Analysis/array-struct-region.cpp index f610fbb2..22fbf2f 100644 --- a/clang/test/Analysis/array-struct-region.cpp +++ b/clang/test/Analysis/array-struct-region.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s void clang_analyzer_eval(int); @@ -11,7 +13,14 @@ struct S { #endif }; +#ifdef INLINE +struct S getS() { + struct S s = { 42 }; + return s; +} +#else struct S getS(); +#endif void testAssignment() {