From e720ce7a3b1c1bfa5f7482183caa6e31fca9a3fb Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 30 Apr 2012 23:23:55 +0000 Subject: [PATCH] When going through references to check if the function returns the address of a local variable, make sure we don't infinitely recurse when the reference binds to itself. e.g: int* func() { int& i = i; // assign non-exist variable to a reference which has same name. return &i; // return pointer } rdar://11345441 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155856 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaChecking.cpp | 58 +++++++++++++++++++-------------- test/Analysis/stack-addr-ps.cpp | 6 ++++ 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index a9557a5474..979a646442 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -3017,8 +3017,10 @@ void Sema::CheckStrncatArguments(const CallExpr *CE, //===--- CHECK: Return Address of Stack Variable --------------------------===// -static Expr *EvalVal(Expr *E, SmallVectorImpl &refVars); -static Expr *EvalAddr(Expr* E, SmallVectorImpl &refVars); +static Expr *EvalVal(Expr *E, SmallVectorImpl &refVars, + Decl *ParentDecl); +static Expr *EvalAddr(Expr* E, SmallVectorImpl &refVars, + Decl *ParentDecl); /// CheckReturnStackAddr - Check if a return statement returns the address /// of a stack variable. @@ -3033,9 +3035,9 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, // label addresses or references to temporaries. if (lhsType->isPointerType() || (!getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) { - stackE = EvalAddr(RetValExp, refVars); + stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/0); } else if (lhsType->isReferenceType()) { - stackE = EvalVal(RetValExp, refVars); + stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/0); } if (stackE == 0) @@ -3109,7 +3111,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, /// * arbitrary interplay between "&" and "*" operators /// * pointer arithmetic from an address of a stack variable /// * taking the address of an array element where the array is on the stack -static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { +static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars, + Decl *ParentDecl) { if (E->isTypeDependent()) return NULL; @@ -3135,7 +3138,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { V->getType()->isReferenceType() && V->hasInit()) { // Add the reference variable to the "trail". refVars.push_back(DR); - return EvalAddr(V->getInit(), refVars); + return EvalAddr(V->getInit(), refVars, ParentDecl); } return NULL; @@ -3147,7 +3150,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { UnaryOperator *U = cast(E); if (U->getOpcode() == UO_AddrOf) - return EvalVal(U->getSubExpr(), refVars); + return EvalVal(U->getSubExpr(), refVars, ParentDecl); else return NULL; } @@ -3168,7 +3171,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { if (!Base->getType()->isPointerType()) Base = B->getRHS(); assert (Base->getType()->isPointerType()); - return EvalAddr(Base, refVars); + return EvalAddr(Base, refVars, ParentDecl); } // For conditional operators we need to see if either the LHS or RHS are @@ -3180,7 +3183,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { if (Expr *lhsExpr = C->getLHS()) { // In C++, we can have a throw-expression, which has 'void' type. if (!lhsExpr->getType()->isVoidType()) - if (Expr* LHS = EvalAddr(lhsExpr, refVars)) + if (Expr* LHS = EvalAddr(lhsExpr, refVars, ParentDecl)) return LHS; } @@ -3188,7 +3191,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { if (C->getRHS()->getType()->isVoidType()) return NULL; - return EvalAddr(C->getRHS(), refVars); + return EvalAddr(C->getRHS(), refVars, ParentDecl); } case Stmt::BlockExprClass: @@ -3200,7 +3203,8 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { return E; // address of label. case Stmt::ExprWithCleanupsClass: - return EvalAddr(cast(E)->getSubExpr(), refVars); + return EvalAddr(cast(E)->getSubExpr(), refVars, + ParentDecl); // For casts, we need to handle conversions from arrays to // pointer values, and pointer-to-pointer conversions. @@ -3224,10 +3228,10 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: - return EvalAddr(SubExpr, refVars); + return EvalAddr(SubExpr, refVars, ParentDecl); case CK_ArrayToPointerDecay: - return EvalVal(SubExpr, refVars); + return EvalVal(SubExpr, refVars, ParentDecl); default: return 0; @@ -3237,7 +3241,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { case Stmt::MaterializeTemporaryExprClass: if (Expr *Result = EvalAddr( cast(E)->GetTemporaryExpr(), - refVars)) + refVars, ParentDecl)) return Result; return E; @@ -3251,7 +3255,8 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl &refVars) { /// EvalVal - This function is complements EvalAddr in the mutual recursion. /// See the comments for EvalAddr for more details. -static Expr *EvalVal(Expr *E, SmallVectorImpl &refVars) { +static Expr *EvalVal(Expr *E, SmallVectorImpl &refVars, + Decl *ParentDecl) { do { // We should only be called for evaluating non-pointer expressions, or // expressions with a pointer type that are not used as references but instead @@ -3273,7 +3278,7 @@ do { } case Stmt::ExprWithCleanupsClass: - return EvalVal(cast(E)->getSubExpr(), refVars); + return EvalVal(cast(E)->getSubExpr(), refVars,ParentDecl); case Stmt::DeclRefExprClass: { // When we hit a DeclRefExpr we are looking at code that refers to a @@ -3281,7 +3286,11 @@ do { // local storage within the function, and if so, return the expression. DeclRefExpr *DR = cast(E); - if (VarDecl *V = dyn_cast(DR->getDecl())) + if (VarDecl *V = dyn_cast(DR->getDecl())) { + // Check if it refers to itself, e.g. "int& i = i;". + if (V == ParentDecl) + return DR; + if (V->hasLocalStorage()) { if (!V->getType()->isReferenceType()) return DR; @@ -3291,9 +3300,10 @@ do { if (V->hasInit()) { // Add the reference variable to the "trail". refVars.push_back(DR); - return EvalVal(V->getInit(), refVars); + return EvalVal(V->getInit(), refVars, V); } } + } return NULL; } @@ -3305,7 +3315,7 @@ do { UnaryOperator *U = cast(E); if (U->getOpcode() == UO_Deref) - return EvalAddr(U->getSubExpr(), refVars); + return EvalAddr(U->getSubExpr(), refVars, ParentDecl); return NULL; } @@ -3314,7 +3324,7 @@ do { // Array subscripts are potential references to data on the stack. We // retrieve the DeclRefExpr* for the array variable if it indeed // has local storage. - return EvalAddr(cast(E)->getBase(), refVars); + return EvalAddr(cast(E)->getBase(), refVars,ParentDecl); } case Stmt::ConditionalOperatorClass: { @@ -3324,10 +3334,10 @@ do { // Handle the GNU extension for missing LHS. if (Expr *lhsExpr = C->getLHS()) - if (Expr *LHS = EvalVal(lhsExpr, refVars)) + if (Expr *LHS = EvalVal(lhsExpr, refVars, ParentDecl)) return LHS; - return EvalVal(C->getRHS(), refVars); + return EvalVal(C->getRHS(), refVars, ParentDecl); } // Accesses to members are potential references to data on the stack. @@ -3343,13 +3353,13 @@ do { if (M->getMemberDecl()->getType()->isReferenceType()) return NULL; - return EvalVal(M->getBase(), refVars); + return EvalVal(M->getBase(), refVars, ParentDecl); } case Stmt::MaterializeTemporaryExprClass: if (Expr *Result = EvalVal( cast(E)->GetTemporaryExpr(), - refVars)) + refVars, ParentDecl)) return Result; return E; diff --git a/test/Analysis/stack-addr-ps.cpp b/test/Analysis/stack-addr-ps.cpp index b09e435608..b21a03dc38 100644 --- a/test/Analysis/stack-addr-ps.cpp +++ b/test/Analysis/stack-addr-ps.cpp @@ -84,3 +84,9 @@ struct TS { return x; } }; + +// rdar://11345441 +int* f5() { + int& i = i; // expected-warning {{Assigned value is garbage or undefined}} expected-note {{binding reference variable 'i' here}} + return &i; // expected-warning {{address of stack memory associated with local variable 'i' returned}} +} -- 2.40.0