forked from OSchip/llvm-project
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:
parent
faded5bb0f
commit
b4015e1877
|
@ -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;
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue