From 13e0573a0e83ed2b2d8fc7daf7596c96c4377fb3 Mon Sep 17 00:00:00 2001 From: Michael Beck Date: Tue, 11 Dec 2007 21:07:44 +0000 Subject: [PATCH] issue a warning if returning the address of a local variable [r18678] --- parser.c | 46 ++++++++++++++++++++++++++++++-- parsetest/shouldfail/ref_local.c | 9 +++++++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 parsetest/shouldfail/ref_local.c diff --git a/parser.c b/parser.c index 0dfaec2..b81115c 100644 --- a/parser.c +++ b/parser.c @@ -5063,6 +5063,38 @@ static statement_t *parse_break(void) return statement; } +/** + * Check if a given declaration represents a local variable. + */ +static bool is_local_var_declaration(const declaration_t *declaration) { + switch ((storage_class_tag_t) declaration->storage_class) { + case STORAGE_CLASS_NONE: + case STORAGE_CLASS_AUTO: + case STORAGE_CLASS_REGISTER: { + const type_t *type = skip_typeref(declaration->type); + if(is_type_function(type)) { + return false; + } else { + return true; + } + } + default: + return false; + } +} + +/** + * Check if a given expression represents a local variable. + */ +static bool is_local_variable(const expression_t *expression) +{ + if (expression->base.kind != EXPR_REFERENCE) { + return false; + } + const declaration_t *declaration = expression->reference.declaration; + return is_local_var_declaration(declaration); +} + /** * Parse a return statement. */ @@ -5097,16 +5129,26 @@ static statement_t *parse_return(void) if(is_type_atomic(return_type, ATOMIC_TYPE_VOID) && !is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) { - warningf(HERE, "'return' with a value, in function returning void"); + warningf(statement->statement.source_position, + "'return' with a value, in function returning void"); return_value = NULL; } else { if(return_type != NULL) { semantic_assign(return_type, &return_value, "'return'"); } } + /* check for returning address of a local var */ + if (return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) { + const expression_t *expression = return_value->unary.value; + if (is_local_variable(expression)) { + warningf(statement->statement.source_position, + "function returns address of local variable"); + } + } } else { if(!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) { - warningf(HERE, "'return' without value, in function returning non-void"); + warningf(statement->statement.source_position, + "'return' without value, in function returning non-void"); } } statement->return_value = return_value; diff --git a/parsetest/shouldfail/ref_local.c b/parsetest/shouldfail/ref_local.c new file mode 100644 index 0000000..44112ac --- /dev/null +++ b/parsetest/shouldfail/ref_local.c @@ -0,0 +1,9 @@ +int *test(void) { + int x = 3; + + return &x; +} + +int main() { + return *test(); +} -- 2.20.1