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

llvm-svn: 155856
This commit is contained in:
Argyrios Kyrtzidis 2012-04-30 23:23:55 +00:00
parent faded5bb0f
commit b4015e1877
2 changed files with 40 additions and 24 deletions

View File

@ -3017,8 +3017,10 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
//===--- CHECK: Return Address of Stack Variable --------------------------===//
static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars);
static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars);
static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
Decl *ParentDecl);
static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &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<DeclRefExpr *> &refVars) {
static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
Decl *ParentDecl) {
if (E->isTypeDependent())
return NULL;
@ -3135,7 +3138,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &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<DeclRefExpr *> &refVars) {
UnaryOperator *U = cast<UnaryOperator>(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<DeclRefExpr *> &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<DeclRefExpr *> &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<DeclRefExpr *> &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<DeclRefExpr *> &refVars) {
return E; // address of label.
case Stmt::ExprWithCleanupsClass:
return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
return EvalAddr(cast<ExprWithCleanups>(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<DeclRefExpr *> &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<DeclRefExpr *> &refVars) {
case Stmt::MaterializeTemporaryExprClass:
if (Expr *Result = EvalAddr(
cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
refVars))
refVars, ParentDecl))
return Result;
return E;
@ -3251,7 +3255,8 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &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<DeclRefExpr *> &refVars) {
static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &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<ExprWithCleanups>(E)->getSubExpr(), refVars);
return EvalVal(cast<ExprWithCleanups>(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<DeclRefExpr>(E);
if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
if (VarDecl *V = dyn_cast<VarDecl>(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<UnaryOperator>(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<ArraySubscriptExpr>(E)->getBase(), refVars);
return EvalAddr(cast<ArraySubscriptExpr>(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<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
refVars))
refVars, ParentDecl))
return Result;
return E;

View File

@ -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}}
}