On 5/22/19 3:34 PM, Martin Sebor wrote: > -Wreturn-local-addr detects a subset of instances of returning > the address of a local object from a function but the warning > doesn't try to handle alloca or VLAs, or some non-trivial cases > of ordinary automatic variables[1]. > > The attached patch extends the implementation of the warning to > detect those. It still doesn't detect instances where the address > is the result of a built-in such strcpy[2]. > > Tested on x86_64-linux. > > Martin > > [1] For example, this is only diagnosed with the patch: > > void* f (int i) > { > struct S { int a[2]; } s[2]; > return &s->a[i]; > } > > [2] The following is not diagnosed even with the patch: > > void sink (void*); > > void* f (int i) > { > char a[6]; > char *p = __builtin_strcpy (a, "123"); > sink (p); > return p; > } > > I would expect detecting to be possible and useful. Maybe as > a follow-up. > > gcc-71924.diff > > PR middle-end/71924 - missing -Wreturn-local-addr returning alloca result > PR middle-end/90549 - missing -Wreturn-local-addr maybe returning an address > of a local array plus offset > > gcc/ChangeLog: > > PR c/71924 > * gimple-ssa-isolate-paths.c (is_addr_local): New function. > (warn_return_addr_local_phi_arg, warn_return_addr_local): Same. > (find_implicit_erroneous_behavior): Call warn_return_addr_local_phi_arg. > (find_explicit_erroneous_behavior): Call warn_return_addr_local. > > gcc/testsuite/ChangeLog: > > PR c/71924 > * gcc.dg/Wreturn-local-addr-2.c: New test. > * gcc.dg/Walloca-4.c: Prune expected warnings. > * gcc.dg/pr41551.c: Same. > * gcc.dg/pr59523.c: Same. > * gcc.dg/tree-ssa/pr88775-2.c: Same. > * gcc.dg/winline-7.c: Same. > > diff --git a/gcc/gimple-ssa-isolate-paths.c b/gcc/gimple-ssa-isolate-paths.c > index 33fe352bb23..2933ecf502e 100644 > --- a/gcc/gimple-ssa-isolate-paths.c > +++ b/gcc/gimple-ssa-isolate-paths.c > @@ -341,6 +341,135 @@ stmt_uses_0_or_null_in_undefined_way (gimple *stmt) > return false; > } > > +/* Return true if EXPR is a expression of pointer type that refers > + to the address of a variable with automatic storage duration. > + If so, set *PLOC to the location of the object or the call that > + allocated it (for alloca and VLAs). When PMAYBE is non-null, > + also consider PHI statements and set *PMAYBE when some but not > + all arguments of such statements refer to local variables, and > + to clear it otherwise. */ > + > +static bool > +is_addr_local (tree exp, location_t *ploc, bool *pmaybe = NULL, > + hash_set<gphi *> *visited = NULL) > +{ > + if (TREE_CODE (exp) == ADDR_EXPR) > + { > + tree baseaddr = get_base_address (TREE_OPERAND (exp, 0)); > + if (TREE_CODE (baseaddr) == MEM_REF) > + return is_addr_local (TREE_OPERAND (baseaddr, 0), ploc, pmaybe, > visited); > + > + if ((!VAR_P (baseaddr) > + || is_global_var (baseaddr)) > + && TREE_CODE (baseaddr) != PARM_DECL) > + return false; > + > + *ploc = DECL_SOURCE_LOCATION (baseaddr); > + return true; > + } > + > + if (TREE_CODE (exp) == SSA_NAME) > + { > + gimple *def_stmt = SSA_NAME_DEF_STMT (exp); > + enum gimple_code code = gimple_code (def_stmt); > + > + if (is_gimple_assign (def_stmt)) > + { > + tree type = TREE_TYPE (gimple_assign_lhs (def_stmt)); > + if (POINTER_TYPE_P (type)) > + { > + tree ptr = gimple_assign_rhs1 (def_stmt); > + return is_addr_local (ptr, ploc, pmaybe, visited); > + } > + return false; > + } > + > + if (code == GIMPLE_CALL > + && gimple_call_builtin_p (def_stmt)) > + { > + tree fn = gimple_call_fndecl (def_stmt); > + int code = DECL_FUNCTION_CODE (fn); > + if (code != BUILT_IN_ALLOCA > + && code != BUILT_IN_ALLOCA_WITH_ALIGN) > + return false; > + > + *ploc = gimple_location (def_stmt); > + return true; > + } > + > + if (code == GIMPLE_PHI && pmaybe) > + { > + unsigned count = 0; > + gphi *phi_stmt = as_a <gphi *> (def_stmt); > + > + unsigned nargs = gimple_phi_num_args (phi_stmt); > + for (unsigned i = 0; i < nargs; ++i) > + { > + if (!visited->add (phi_stmt)) > + { > + tree arg = gimple_phi_arg_def (phi_stmt, i); > + if (is_addr_local (arg, ploc, pmaybe, visited)) > + ++count; > + } > + } > + > + *pmaybe = count && count < nargs; > + return count != 0; > + } > + } > + > + return false; > +} Is there some reason you didn't query the alias oracle here? It would seem a fairly natural fit. Ultimately given a pointer (which will be an SSA_NAME) you want to ask whether or not it conclusively points into the stack.
That would seem to dramatically simplify is_addr_local. The rest looks pretty reasonable. Jeff