aboutsummaryrefslogtreecommitdiff
path: root/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Sema/SemaChecking.cpp')
-rw-r--r--Sema/SemaChecking.cpp229
1 files changed, 227 insertions, 2 deletions
diff --git a/Sema/SemaChecking.cpp b/Sema/SemaChecking.cpp
index 1917d6317d..d699e1bcf8 100644
--- a/Sema/SemaChecking.cpp
+++ b/Sema/SemaChecking.cpp
@@ -71,7 +71,7 @@ Sema::CheckFunctionCall(Expr *Fn,
}
CheckPrintfArguments(Fn, LParenLoc, RParenLoc, HasVAListArg,
- FDecl, format_idx, Args, NumArgsInCall);
+ FDecl, format_idx, Args, NumArgsInCall);
}
return false;
@@ -347,7 +347,7 @@ Sema::CheckPrintfArguments(Expr *Fn,
LastConversionIdx+1);
Diag(Loc, diag::warn_printf_invalid_conversion,
- std::string(Str+LastConversionIdx, Str+StrIdx),
+ std::string(Str+LastConversionIdx, Str+StrIdx),
Fn->getSourceRange());
return;
}
@@ -370,3 +370,228 @@ Sema::CheckPrintfArguments(Expr *Fn,
diag::warn_printf_too_many_data_args, Fn->getSourceRange());
}
}
+
+//===--- CHECK: Return Address of Stack Variable --------------------------===//
+
+static DeclRefExpr* EvalVal(Expr *E);
+static DeclRefExpr* EvalAddr(Expr* E);
+
+/// CheckReturnStackAddr - Check if a return statement returns the address
+/// of a stack variable.
+void
+Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
+ SourceLocation ReturnLoc) {
+
+ // Perform checking for returned stack addresses.
+ if (lhsType->isPointerType()) {
+ if (DeclRefExpr *DR = EvalAddr(RetValExp))
+ Diag(DR->getLocStart(), diag::warn_ret_stack_addr,
+ DR->getDecl()->getIdentifier()->getName(),
+ RetValExp->getSourceRange());
+ }
+ // Perform checking for stack values returned by reference.
+ else if (lhsType->isReferenceType()) {
+ if (DeclRefExpr *DR = EvalVal(RetValExp))
+ Diag(DR->getLocStart(), diag::warn_ret_stack_ref,
+ DR->getDecl()->getIdentifier()->getName(),
+ RetValExp->getSourceRange());
+ }
+}
+
+/// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that
+/// check if the expression in a return statement evaluates to an address
+/// to a location on the stack. The recursion is used to traverse the
+/// AST of the return expression, with recursion backtracking when we
+/// encounter a subexpression that (1) clearly does not lead to the address
+/// of a stack variable or (2) is something we cannot determine leads to
+/// the address of a stack variable based on such local checking.
+///
+/// EvalAddr processes expressions that are pointers, and EvalVal handles
+/// expressions that are rvalues or variable references.
+/// At the base case of the recursion is a check for a DeclRefExpr* in
+/// the refers to a stack variable.
+///
+/// This implementation handles:
+///
+/// * pointer-to-pointer casts
+/// * implicit conversions from array references to pointers
+/// * taking the address of fields
+/// * 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 DeclRefExpr* EvalAddr(Expr *E) {
+
+ // We should only be called for evaluating pointer expressions.
+ assert (E->getType()->isPointerType() && "EvalAddr only works on pointers");
+
+ // Our "symbolic interpreter" is just a dispatch off the currently
+ // viewed AST node. We then recursively traverse the AST by calling
+ // EvalAddr and EvalVal appropriately.
+ switch (E->getStmtClass()) {
+
+ case Stmt::ParenExprClass:
+ // Ignore parentheses.
+ return EvalAddr(cast<ParenExpr>(E)->getSubExpr());
+
+ case Stmt::UnaryOperatorClass: {
+ // The only unary operator that make sense to handle here
+ // is AddrOf. All others don't make sense as pointers.
+ UnaryOperator *U = cast<UnaryOperator>(E);
+
+ if (U->getOpcode() == UnaryOperator::AddrOf)
+ return EvalVal(U->getSubExpr());
+ else
+ return NULL;
+ }
+
+ case Stmt::BinaryOperatorClass: {
+ // Handle pointer arithmetic. All other binary operators are not valid
+ // in this context.
+ BinaryOperator *B = cast<BinaryOperator>(E);
+ BinaryOperator::Opcode op = B->getOpcode();
+
+ if (op != BinaryOperator::Add && op != BinaryOperator::Sub)
+ return NULL;
+
+ Expr *Base = B->getLHS();
+
+ // Determine which argument is the real pointer base. It could be
+ // the RHS argument instead of the LHS.
+ if (!Base->getType()->isPointerType()) Base = B->getRHS();
+
+ assert (Base->getType()->isPointerType());
+ return EvalAddr(Base);
+ }
+
+ // For conditional operators we need to see if either the LHS or RHS are
+ // valid DeclRefExpr*s. If one of them is valid, we return it.
+ case Stmt::ConditionalOperatorClass: {
+ ConditionalOperator *C = cast<ConditionalOperator>(E);
+
+ if (DeclRefExpr* LHS = EvalAddr(C->getLHS()))
+ return LHS;
+ else
+ return EvalAddr(C->getRHS());
+ }
+
+ // For implicit casts, we need to handle conversions from arrays to
+ // pointer values, and implicit pointer-to-pointer conversions.
+ case Stmt::ImplicitCastExprClass: {
+ ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E);
+ Expr* SubExpr = IE->getSubExpr();
+
+ if (SubExpr->getType()->isPointerType())
+ return EvalAddr(SubExpr);
+ else
+ return EvalVal(SubExpr);
+ }
+
+ // For casts, we handle pointer-to-pointer conversions (which
+ // is essentially a no-op from our mini-interpreter's standpoint).
+ // For other casts we abort.
+ case Stmt::CastExprClass: {
+ CastExpr *C = cast<CastExpr>(E);
+ Expr *SubExpr = C->getSubExpr();
+
+ if (SubExpr->getType()->isPointerType())
+ return EvalAddr(SubExpr);
+ else
+ return NULL;
+ }
+
+ // TODO: C++ casts.
+ case Stmt::CXXCastExprClass:
+ return NULL;
+
+ // Everything else: we simply don't reason about them.
+ default:
+ return NULL;
+ }
+}
+
+
+/// EvalVal - This function is complements EvalAddr in the mutual recursion.
+/// See the comments for EvalAddr for more details.
+static DeclRefExpr* EvalVal(Expr *E) {
+
+ // We should only be called for evaluating non-pointer expressions.
+ assert (!E->getType()->isPointerType() && "EvalVal doesn't work on pointers");
+
+ // Our "symbolic interpreter" is just a dispatch off the currently
+ // viewed AST node. We then recursively traverse the AST by calling
+ // EvalAddr and EvalVal appropriately.
+ switch (E->getStmtClass()) {
+
+ case Stmt::DeclRefExprClass: {
+ // DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking
+ // at code that refers to a variable's name. We check if it has 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(V->hasLocalStorage()) return DR;
+
+ return NULL;
+ }
+
+ case Stmt::ParenExprClass:
+ // Ignore parentheses.
+ return EvalVal(cast<ParenExpr>(E)->getSubExpr());
+
+ case Stmt::UnaryOperatorClass: {
+ // The only unary operator that make sense to handle here
+ // is Deref. All others don't resolve to a "name." This includes
+ // handling all sorts of rvalues passed to a unary operator.
+ UnaryOperator *U = cast<UnaryOperator>(E);
+
+ if (U->getOpcode() == UnaryOperator::Deref)
+ return EvalAddr(U->getSubExpr());
+
+ return NULL;
+ }
+
+ case Stmt::ArraySubscriptExprClass: {
+ // Array subscripts are potential references to data on the stack. We
+ // retrieve the DeclRefExpr* for the array variable if it indeed
+ // has local storage.
+ ArraySubscriptExpr *A = cast<ArraySubscriptExpr>(E);
+
+ // The array access could be written A[4] or 4[A] (both are equivalent).
+ // In the second case, the "base" is the offset and the "Idx" is
+ // the base. We test for this case by seeing if the Base expression
+ // has a pointer type.
+ Expr* Base = A->getBase();
+
+ if (Base->getType()->isPointerType())
+ return EvalAddr(Base);
+ else
+ return EvalAddr(A->getIdx());
+ }
+
+ case Stmt::ConditionalOperatorClass: {
+ // For conditional operators we need to see if either the LHS or RHS are
+ // non-NULL DeclRefExpr's. If one is non-NULL, we return it.
+ ConditionalOperator *C = cast<ConditionalOperator>(E);
+
+ if (DeclRefExpr *LHS = EvalVal(C->getLHS()))
+ return LHS;
+ else
+ return EvalVal(C->getRHS());
+ }
+
+ // Accesses to members are potential references to data on the stack.
+ case Stmt::MemberExprClass: {
+ MemberExpr *M = cast<MemberExpr>(E);
+
+ // Check for indirect access. We only want direct field accesses.
+ if (!M->isArrow())
+ return EvalVal(M->getBase());
+ else
+ return NULL;
+ }
+
+ // Everything else: we simply don't reason about them.
+ default:
+ return NULL;
+ }
+}