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 --------------------------===//
|
//===--- CHECK: Return Address of Stack Variable --------------------------===//
|
||||||
|
|
||||||
static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars);
|
static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
|
||||||
static Expr *EvalAddr(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
|
/// CheckReturnStackAddr - Check if a return statement returns the address
|
||||||
/// of a stack variable.
|
/// of a stack variable.
|
||||||
|
@ -3033,9 +3035,9 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
|
||||||
// label addresses or references to temporaries.
|
// label addresses or references to temporaries.
|
||||||
if (lhsType->isPointerType() ||
|
if (lhsType->isPointerType() ||
|
||||||
(!getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
|
(!getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
|
||||||
stackE = EvalAddr(RetValExp, refVars);
|
stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/0);
|
||||||
} else if (lhsType->isReferenceType()) {
|
} else if (lhsType->isReferenceType()) {
|
||||||
stackE = EvalVal(RetValExp, refVars);
|
stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackE == 0)
|
if (stackE == 0)
|
||||||
|
@ -3109,7 +3111,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
|
||||||
/// * arbitrary interplay between "&" and "*" operators
|
/// * arbitrary interplay between "&" and "*" operators
|
||||||
/// * pointer arithmetic from an address of a stack variable
|
/// * pointer arithmetic from an address of a stack variable
|
||||||
/// * taking the address of an array element where the array is on the stack
|
/// * 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())
|
if (E->isTypeDependent())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -3135,7 +3138,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
|
||||||
V->getType()->isReferenceType() && V->hasInit()) {
|
V->getType()->isReferenceType() && V->hasInit()) {
|
||||||
// Add the reference variable to the "trail".
|
// Add the reference variable to the "trail".
|
||||||
refVars.push_back(DR);
|
refVars.push_back(DR);
|
||||||
return EvalAddr(V->getInit(), refVars);
|
return EvalAddr(V->getInit(), refVars, ParentDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -3147,7 +3150,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
|
||||||
UnaryOperator *U = cast<UnaryOperator>(E);
|
UnaryOperator *U = cast<UnaryOperator>(E);
|
||||||
|
|
||||||
if (U->getOpcode() == UO_AddrOf)
|
if (U->getOpcode() == UO_AddrOf)
|
||||||
return EvalVal(U->getSubExpr(), refVars);
|
return EvalVal(U->getSubExpr(), refVars, ParentDecl);
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -3168,7 +3171,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
|
||||||
if (!Base->getType()->isPointerType()) Base = B->getRHS();
|
if (!Base->getType()->isPointerType()) Base = B->getRHS();
|
||||||
|
|
||||||
assert (Base->getType()->isPointerType());
|
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
|
// 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()) {
|
if (Expr *lhsExpr = C->getLHS()) {
|
||||||
// In C++, we can have a throw-expression, which has 'void' type.
|
// In C++, we can have a throw-expression, which has 'void' type.
|
||||||
if (!lhsExpr->getType()->isVoidType())
|
if (!lhsExpr->getType()->isVoidType())
|
||||||
if (Expr* LHS = EvalAddr(lhsExpr, refVars))
|
if (Expr* LHS = EvalAddr(lhsExpr, refVars, ParentDecl))
|
||||||
return LHS;
|
return LHS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3188,7 +3191,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
|
||||||
if (C->getRHS()->getType()->isVoidType())
|
if (C->getRHS()->getType()->isVoidType())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return EvalAddr(C->getRHS(), refVars);
|
return EvalAddr(C->getRHS(), refVars, ParentDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Stmt::BlockExprClass:
|
case Stmt::BlockExprClass:
|
||||||
|
@ -3200,7 +3203,8 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
|
||||||
return E; // address of label.
|
return E; // address of label.
|
||||||
|
|
||||||
case Stmt::ExprWithCleanupsClass:
|
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
|
// For casts, we need to handle conversions from arrays to
|
||||||
// pointer values, and pointer-to-pointer conversions.
|
// pointer values, and pointer-to-pointer conversions.
|
||||||
|
@ -3224,10 +3228,10 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
|
||||||
case CK_CPointerToObjCPointerCast:
|
case CK_CPointerToObjCPointerCast:
|
||||||
case CK_BlockPointerToObjCPointerCast:
|
case CK_BlockPointerToObjCPointerCast:
|
||||||
case CK_AnyPointerToBlockPointerCast:
|
case CK_AnyPointerToBlockPointerCast:
|
||||||
return EvalAddr(SubExpr, refVars);
|
return EvalAddr(SubExpr, refVars, ParentDecl);
|
||||||
|
|
||||||
case CK_ArrayToPointerDecay:
|
case CK_ArrayToPointerDecay:
|
||||||
return EvalVal(SubExpr, refVars);
|
return EvalVal(SubExpr, refVars, ParentDecl);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3237,7 +3241,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
|
||||||
case Stmt::MaterializeTemporaryExprClass:
|
case Stmt::MaterializeTemporaryExprClass:
|
||||||
if (Expr *Result = EvalAddr(
|
if (Expr *Result = EvalAddr(
|
||||||
cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
|
cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
|
||||||
refVars))
|
refVars, ParentDecl))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
return E;
|
return E;
|
||||||
|
@ -3251,7 +3255,8 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
|
||||||
|
|
||||||
/// EvalVal - This function is complements EvalAddr in the mutual recursion.
|
/// EvalVal - This function is complements EvalAddr in the mutual recursion.
|
||||||
/// See the comments for EvalAddr for more details.
|
/// 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 {
|
do {
|
||||||
// We should only be called for evaluating non-pointer expressions, or
|
// We should only be called for evaluating non-pointer expressions, or
|
||||||
// expressions with a pointer type that are not used as references but instead
|
// expressions with a pointer type that are not used as references but instead
|
||||||
|
@ -3273,7 +3278,7 @@ do {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Stmt::ExprWithCleanupsClass:
|
case Stmt::ExprWithCleanupsClass:
|
||||||
return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
|
return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars,ParentDecl);
|
||||||
|
|
||||||
case Stmt::DeclRefExprClass: {
|
case Stmt::DeclRefExprClass: {
|
||||||
// When we hit a DeclRefExpr we are looking at code that refers to a
|
// 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.
|
// local storage within the function, and if so, return the expression.
|
||||||
DeclRefExpr *DR = cast<DeclRefExpr>(E);
|
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->hasLocalStorage()) {
|
||||||
if (!V->getType()->isReferenceType())
|
if (!V->getType()->isReferenceType())
|
||||||
return DR;
|
return DR;
|
||||||
|
@ -3291,9 +3300,10 @@ do {
|
||||||
if (V->hasInit()) {
|
if (V->hasInit()) {
|
||||||
// Add the reference variable to the "trail".
|
// Add the reference variable to the "trail".
|
||||||
refVars.push_back(DR);
|
refVars.push_back(DR);
|
||||||
return EvalVal(V->getInit(), refVars);
|
return EvalVal(V->getInit(), refVars, V);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -3305,7 +3315,7 @@ do {
|
||||||
UnaryOperator *U = cast<UnaryOperator>(E);
|
UnaryOperator *U = cast<UnaryOperator>(E);
|
||||||
|
|
||||||
if (U->getOpcode() == UO_Deref)
|
if (U->getOpcode() == UO_Deref)
|
||||||
return EvalAddr(U->getSubExpr(), refVars);
|
return EvalAddr(U->getSubExpr(), refVars, ParentDecl);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -3314,7 +3324,7 @@ do {
|
||||||
// Array subscripts are potential references to data on the stack. We
|
// Array subscripts are potential references to data on the stack. We
|
||||||
// retrieve the DeclRefExpr* for the array variable if it indeed
|
// retrieve the DeclRefExpr* for the array variable if it indeed
|
||||||
// has local storage.
|
// has local storage.
|
||||||
return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars);
|
return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars,ParentDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Stmt::ConditionalOperatorClass: {
|
case Stmt::ConditionalOperatorClass: {
|
||||||
|
@ -3324,10 +3334,10 @@ do {
|
||||||
|
|
||||||
// Handle the GNU extension for missing LHS.
|
// Handle the GNU extension for missing LHS.
|
||||||
if (Expr *lhsExpr = C->getLHS())
|
if (Expr *lhsExpr = C->getLHS())
|
||||||
if (Expr *LHS = EvalVal(lhsExpr, refVars))
|
if (Expr *LHS = EvalVal(lhsExpr, refVars, ParentDecl))
|
||||||
return LHS;
|
return LHS;
|
||||||
|
|
||||||
return EvalVal(C->getRHS(), refVars);
|
return EvalVal(C->getRHS(), refVars, ParentDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accesses to members are potential references to data on the stack.
|
// Accesses to members are potential references to data on the stack.
|
||||||
|
@ -3343,13 +3353,13 @@ do {
|
||||||
if (M->getMemberDecl()->getType()->isReferenceType())
|
if (M->getMemberDecl()->getType()->isReferenceType())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return EvalVal(M->getBase(), refVars);
|
return EvalVal(M->getBase(), refVars, ParentDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Stmt::MaterializeTemporaryExprClass:
|
case Stmt::MaterializeTemporaryExprClass:
|
||||||
if (Expr *Result = EvalVal(
|
if (Expr *Result = EvalVal(
|
||||||
cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
|
cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
|
||||||
refVars))
|
refVars, ParentDecl))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
return E;
|
return E;
|
||||||
|
|
|
@ -84,3 +84,9 @@ struct TS {
|
||||||
return x;
|
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