Hi, Andi

> On Oct 30, 2024, at 12:15, Andi Kleen <a...@linux.intel.com> wrote:
> 
> Qing Zhao <qing.z...@oracle.com> writes:
> 
>> Control this with a new option -fdiagnostics-details.
> 
> It would be useful to be also able to print the inline call stack,
> maybe with a separate option.

Thank you for the suggestion. 
Yes, inline call stack will also be very helpful to the users to understand the 
warning message better.

I noticed that currently,  some inlining information has already been issued 
when reporting warning. For example, 
For the testing case of PR115274, when it was compiled with -O2 -Wall, we got:

$ cat t_115274.c
#include <string.h>
char *c;
void a();
int b(char *d) { return strlen(d); }
void e() {
  long f = 1;
  f = b(c + f);
  if (c == 0)
    a(f);
}

$/home/opc/Install/latest-d/bin/gcc -O2 -Wall t_115274.c
In function ‘b’,
    inlined from ‘e’ at t_115274.c:7:7:
t_115274.c:4:25: warning: ‘strlen’ reading 1 or more bytes from a region of 
size 0 [-Wstringop-overread]
    4 | int b(char *d) { return strlen(d); }
      |                         ^~~~~~~~~
In function ‘e’:
cc1: note: source object is likely at address zero.

I located that the following routine in gcc/langhooks.cc <http://langhooks.cc/> 
reports the inlining information when reporting an error.

/* The default function to print out name of current function that caused
   an error.  */
void
lhd_print_error_function (diagnostic_text_output_format &text_output,
                          const char *file,
                          const diagnostic_info *diagnostic)

So, I am wondering whether there already is some available utility routine we 
can use to report the inlining chain for one location? 

Thanks.

Qing


> 
> In some array bounds cases I looked at the problem was hidden in some inlines
> and it wasn't trivial to figure it out.
> 
> I wrote this patch for it at some point.
> 
> 
>    Print inline stack for warn access warnings
> 
>    The warnings reported by gimple-ssa-warn-access often depend on the
>    caller with inlining, and when there are a lot of callers it can be
>    difficult to figure out which caller triggered a warning.
> 
>    Print the function context including inline stack for these
>    warnings.
> 
>    gcc/ChangeLog:
> 
>            * gimple-ssa-warn-access.cc (maybe_inform_function): New
>            function to report function context.
>            (warn_string_no_nul): Use maybe_inform_function.
>            (maybe_warn_nonstring_arg): Dito.
>            (maybe_warn_for_bound): Dito.
>            (warn_for_access): Dito.
>            (check_access): Dito.
>            (warn_dealloc_offset): Dito.
>            (maybe_warn_alloc_args_overflow): Dito.
>            (pass_waccess::check_strncat): Dito.
>            (pass_waccess::maybe_check_access_sizes): Dito.
>            (pass_waccess::maybe_check_dealloc_call): Dito.
>            (pass_waccess::warn_invalid_pointer): Dito.
>            (maybe_warn_mismatched_realloc): Dito.
>            (pass_waccess::check_dangling_stores): Dito.
>            (pass_waccess::execute): Reset last_function variable.
> 
> diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
> index 61f9f0f3d310..94c043531988 100644
> --- a/gcc/gimple-ssa-warn-access.cc
> +++ b/gcc/gimple-ssa-warn-access.cc
> @@ -125,6 +125,21 @@ call_arg (tree expr, unsigned argno)
>   return CALL_EXPR_ARG (expr, argno);
> }
> 
> +/* Already printed inform for the function.  */
> +static bool printed_function;
> +
> +/* Inform about the function stack unless warning is suppressed at LOC
> +   with opt code OPT.  */
> +static void
> +maybe_inform_function (location_t loc, int opt)
> +{
> +  if (printed_function)
> +    return;
> +  printed_function = true;
> +  if (!warning_suppressed_at (loc, (opt_code)opt))
> +    inform (DECL_SOURCE_LOCATION (cfun->decl), "in function %qD", 
> cfun->decl);
> +}
> +
> /* For a call EXPR at LOC to a function FNAME that expects a string
>    in the argument ARG, issue a diagnostic due to it being a called
>    with an argument that is a character array with no terminating
> @@ -162,6 +177,8 @@ warn_string_no_nul (location_t loc, GimpleOrTree expr, 
> const char *fname,
> 
>   auto_diagnostic_group d;
> 
> +  maybe_inform_function (loc, opt);
> +
>   const tree maxobjsize = max_object_size ();
>   const wide_int maxsiz = wi::to_wide (maxobjsize);
>   if (expr)
> @@ -485,6 +502,7 @@ maybe_warn_nonstring_arg (tree fndecl, GimpleOrTree exp)
>       if (tree_int_cst_lt (maxobjsize, bndrng[0]))
> {
>  bool warned = false;
> +  maybe_inform_function (loc, OPT_Wstringop_overread);
>  if (tree_int_cst_equal (bndrng[0], bndrng[1]))
>    warned = warning_at (loc, OPT_Wstringop_overread,
> "%qD specified bound %E "
> @@ -638,6 +656,7 @@ maybe_warn_nonstring_arg (tree fndecl, GimpleOrTree exp)
>       auto_diagnostic_group d;
>       if (wi::ltu_p (asize, wibnd))
> {
> +  maybe_inform_function (loc, OPT_Wstringop_overread);
>  if (bndrng[0] == bndrng[1])
>    warned = warning_at (loc, OPT_Wstringop_overread,
> "%qD argument %i declared attribute "
> @@ -723,6 +742,7 @@ maybe_warn_for_bound (opt_code opt, location_t loc, 
> GimpleOrTree exp, tree func,
>       auto_diagnostic_group d;
>       if (tree_int_cst_lt (maxobjsize, bndrng[0]))
> {
> +  maybe_inform_function (loc, opt);
>  if (bndrng[0] == bndrng[1])
>    warned = (func
>      ? warning_at (loc, opt,
> @@ -760,7 +780,9 @@ maybe_warn_for_bound (opt_code opt, location_t loc, 
> GimpleOrTree exp, tree func,
>       else if (!size || tree_int_cst_le (bndrng[0], size))
> return false;
>       else if (tree_int_cst_equal (bndrng[0], bndrng[1]))
> - warned = (func
> + {
> +  maybe_inform_function (loc, opt);
> +  warned = (func
>  ? warning_at (loc, opt,
> (maybe
> ? G_("%qD specified bound %E may exceed "
> @@ -775,8 +797,11 @@ maybe_warn_for_bound (opt_code opt, location_t loc, 
> GimpleOrTree exp, tree func,
> : G_("specified bound %E exceeds "
>      "source size %E")),
> bndrng[0], size));
> + }
>       else
> - warned = (func
> + {
> +  maybe_inform_function (loc, opt);
> +  warned = (func
>  ? warning_at (loc, opt,
> (maybe
> ? G_("%qD specified bound [%E, %E] may "
> @@ -791,6 +816,7 @@ maybe_warn_for_bound (opt_code opt, location_t loc, 
> GimpleOrTree exp, tree func,
> : G_("specified bound [%E, %E] exceeds "
>      "source size %E")),
> bndrng[0], bndrng[1], size));
> + }
>       if (warned)
> {
>  if (pad && pad->src.ref
> @@ -816,7 +842,9 @@ maybe_warn_for_bound (opt_code opt, location_t loc, 
> GimpleOrTree exp, tree func,
>   if (tree_int_cst_lt (maxobjsize, bndrng[0]))
>     {
>       if (bndrng[0] == bndrng[1])
> - warned = (func
> + {
> +  maybe_inform_function (loc, opt);
> +  warned = (func
>  ? warning_at (loc, opt,
> (maybe
> ? G_("%qD specified size %E may "
> @@ -831,8 +859,11 @@ maybe_warn_for_bound (opt_code opt, location_t loc, 
> GimpleOrTree exp, tree func,
> : G_("specified size %E exceeds "
>      "maximum object size %E")),
> bndrng[0], maxobjsize));
> + }
>       else
> - warned = (func
> + {
> +  maybe_inform_function (loc, opt);
> +  warned = (func
>  ? warning_at (loc, opt,
> (maybe
> ? G_("%qD specified size between %E and %E "
> @@ -847,11 +878,14 @@ maybe_warn_for_bound (opt_code opt, location_t loc, 
> GimpleOrTree exp, tree func,
> : G_("specified size between %E and %E "
>      "exceeds maximum object size %E")),
> bndrng[0], bndrng[1], maxobjsize));
> +      }
>     }
>   else if (!size || tree_int_cst_le (bndrng[0], size))
>     return false;
>   else if (tree_int_cst_equal (bndrng[0], bndrng[1]))
> -    warned = (func
> +    {
> +      maybe_inform_function (loc, opt);
> +      warned = (func
>      ? warning_at (loc, opt,
>    (maybe
>     ? G_("%qD specified bound %E may exceed "
> @@ -866,8 +900,11 @@ maybe_warn_for_bound (opt_code opt, location_t loc, 
> GimpleOrTree exp, tree func,
>     : G_("specified bound %E exceeds "
>  "destination size %E")),
>    bndrng[0], size));
> +    }
>   else
> -    warned = (func
> +    {
> +      maybe_inform_function (loc, opt);
> +      warned = (func
>      ? warning_at (loc, opt,
>    (maybe
>     ? G_("%qD specified bound [%E, %E] may exceed "
> @@ -882,6 +919,7 @@ maybe_warn_for_bound (opt_code opt, location_t loc, 
> GimpleOrTree exp, tree func,
>     : G_("specified bound [%E, %E] exceeds "
>  "destination size %E")),
>    bndrng[0], bndrng[1], size));
> +    }
> 
>   if (warned)
>     {
> @@ -928,6 +966,7 @@ warn_for_access (location_t loc, tree func, GimpleOrTree 
> exp, int opt,
> 
>   if (write && read)
>     {
> +      maybe_inform_function (loc, opt);
>       if (tree_int_cst_equal (range[0], range[1]))
> warned = (func
>  ? warning_n (loc, opt, tree_to_uhwi (range[0]),
> @@ -994,6 +1033,7 @@ warn_for_access (location_t loc, tree func, GimpleOrTree 
> exp, int opt,
> 
>   if (write)
>     {
> +      maybe_inform_function (loc, opt);
>       if (tree_int_cst_equal (range[0], range[1]))
> warned = (func
>  ? warning_n (loc, opt, tree_to_uhwi (range[0]),
> @@ -1064,6 +1104,7 @@ warn_for_access (location_t loc, tree func, 
> GimpleOrTree exp, int opt,
> 
>   if (read)
>     {
> +      maybe_inform_function (loc, OPT_Wstringop_overread);
>       if (tree_int_cst_equal (range[0], range[1]))
> warned = (func
>  ? warning_n (loc, OPT_Wstringop_overread,
> @@ -1134,6 +1175,7 @@ warn_for_access (location_t loc, tree func, 
> GimpleOrTree exp, int opt,
>       return warned;
>     }
> 
> +  maybe_inform_function (loc, OPT_Wstringop_overread);
>   if (tree_int_cst_equal (range[0], range[1])
>       || tree_int_cst_sign_bit (range[1]))
>     warned = (func
> @@ -1400,6 +1442,7 @@ check_access (GimpleOrTree exp, tree dstwrite,
>  bool warned = false;
>  if (dstwrite == slen && at_least_one)
>    {
> +      maybe_inform_function (loc, opt);
>      /* This is a call to strcpy with a destination of 0 size
> and a source of unknown length.  The call will write
> at least one byte past the end of the destination.  */
> @@ -2046,6 +2089,7 @@ warn_dealloc_offset (location_t loc, gimple *call, 
> const access_ref &aref)
>     }
> 
>   auto_diagnostic_group d;
> +  maybe_inform_function (loc, OPT_Wfree_nonheap_object);
>   if (!warning_at (loc, OPT_Wfree_nonheap_object,
>   "%qD called on pointer %qE with nonzero offset%s",
>   dealloc_decl, aref.ref, offstr))
> @@ -2273,6 +2317,7 @@ maybe_warn_alloc_args_overflow (gimple *stmt, const 
> tree args[2],
> 
>  if (tree_int_cst_lt (args[i], integer_zero_node))
>    {
> +      maybe_inform_function (loc, OPT_Walloc_size_larger_than_);
>      warned = warning_at (loc, OPT_Walloc_size_larger_than_,
>   "argument %i value %qE is negative",
>   idx[i] + 1, args[i]);
> @@ -2290,9 +2335,12 @@ maybe_warn_alloc_args_overflow (gimple *stmt, const 
> tree args[2],
>  ? IDENTIFIER_LENGTH (DECL_NAME (fn)) != 6
>  : !lookup_attribute ("returns_nonnull",
>       TYPE_ATTRIBUTES (fntype)))
> - warned = warning_at (loc, OPT_Walloc_zero,
> + {
> +  maybe_inform_function (loc, OPT_Walloc_size_larger_than_);
> +  warned = warning_at (loc, OPT_Walloc_zero,
>     "argument %i value is zero",
>     idx[i] + 1);
> + }
>    }
>  else if (tree_int_cst_lt (maxobjsize, args[i]))
>    {
> @@ -2308,6 +2356,7 @@ maybe_warn_alloc_args_overflow (gimple *stmt, const 
> tree args[2],
>  && integer_all_onesp (args[i]))
> continue;
> 
> +      maybe_inform_function (loc, OPT_Walloc_size_larger_than_);
>      warned = warning_at (loc, OPT_Walloc_size_larger_than_,
>   "argument %i value %qE exceeds "
>   "maximum object size %E",
> @@ -2322,6 +2371,7 @@ maybe_warn_alloc_args_overflow (gimple *stmt, const 
> tree args[2],
>  if (tree_int_cst_lt (argrange[i][0], integer_zero_node)
>      && tree_int_cst_le (argrange[i][1], integer_zero_node))
>    {
> +      maybe_inform_function (loc, OPT_Walloc_size_larger_than_);
>      warned = warning_at (loc, OPT_Walloc_size_larger_than_,
>   "argument %i range [%E, %E] is negative",
>   idx[i] + 1,
> @@ -2329,6 +2379,7 @@ maybe_warn_alloc_args_overflow (gimple *stmt, const 
> tree args[2],
>    }
>  else if (tree_int_cst_lt (maxobjsize, argrange[i][0]))
>    {
> +      maybe_inform_function (loc, OPT_Walloc_size_larger_than_);
>      warned = warning_at (loc, OPT_Walloc_size_larger_than_,
>   "argument %i range [%E, %E] exceeds "
>   "maximum object size %E",
> @@ -2359,18 +2410,24 @@ maybe_warn_alloc_args_overflow (gimple *stmt, const 
> tree args[2],
>       wide_int prod = wi::umul (x, y, &vflow);
> 
>       if (vflow)
> - warned = warning_at (loc, OPT_Walloc_size_larger_than_,
> + {
> +  maybe_inform_function (loc, OPT_Walloc_size_larger_than_);
> +  warned = warning_at (loc, OPT_Walloc_size_larger_than_,
>     "product %<%E * %E%> of arguments %i and %i "
>     "exceeds %<SIZE_MAX%>",
>     argrange[0][0], argrange[1][0],
>     idx[0] + 1, idx[1] + 1);
> + }
>       else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod))
> - warned = warning_at (loc, OPT_Walloc_size_larger_than_,
> + {
> +  maybe_inform_function (loc, OPT_Walloc_size_larger_than_);
> +  warned = warning_at (loc, OPT_Walloc_size_larger_than_,
>     "product %<%E * %E%> of arguments %i and %i "
>     "exceeds maximum object size %E",
>     argrange[0][0], argrange[1][0],
>     idx[0] + 1, idx[1] + 1,
>     maxobjsize);
> + }
> 
>       if (warned)
> {
> @@ -2563,6 +2620,7 @@ pass_waccess::check_strncat (gcall *stmt)
>       && tree_int_cst_equal (destsize, maxread))
>     {
>       location_t loc = get_location (stmt);
> +      maybe_inform_function (loc, OPT_Wstringop_overflow_);
>       warning_at (loc, OPT_Wstringop_overflow_,
>  "%qD specified bound %E equals destination size",
>  get_callee_fndecl (stmt), maxread);
> @@ -3454,6 +3512,7 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, 
> tree fndecl, tree fntype,
>      const std::string argtypestr
> = access.second.array_as_string (ptrtype);
> 
> +      maybe_inform_function (loc, OPT_Wstringop_overflow_);
>      if (warning_at (loc, OPT_Wstringop_overflow_,
>      "bound argument %i value %s is "
>      "negative for a variable length array "
> @@ -3508,6 +3567,7 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, 
> tree fndecl, tree fntype,
> different from also declaring the pointer argument with
> attribute nonnull when the function accepts null pointers
> only when the corresponding size is zero.  */
> +      maybe_inform_function (loc, OPT_Wnonnull);
>      if (warning_at (loc, OPT_Wnonnull,
>   "argument %i is null but "
>   "the corresponding size argument "
> @@ -3706,6 +3766,7 @@ pass_waccess::maybe_check_dealloc_call (gcall *call)
>       if (aref.ref_declared ())
> {
>  auto_diagnostic_group d;
> +  maybe_inform_function (loc, OPT_Wfree_nonheap_object);
>  if (warning_at (loc, OPT_Wfree_nonheap_object,
>  "%qD called on unallocated object %qD",
>  dealloc_decl, ref))
> @@ -3725,6 +3786,7 @@ pass_waccess::maybe_check_dealloc_call (gcall *call)
>   else if (CONSTANT_CLASS_P (ref))
>     {
>       auto_diagnostic_group d;
> +      maybe_inform_function (loc, OPT_Wfree_nonheap_object);
>       if (warning_at (loc, OPT_Wfree_nonheap_object,
>      "%qD called on a pointer to an unallocated "
>      "object %qE", dealloc_decl, ref))
> @@ -3767,6 +3829,7 @@ pass_waccess::maybe_check_dealloc_call (gcall *call)
>     || DECL_IS_OPERATOR_DELETE_P (dealloc_decl)
>     ? OPT_Wmismatched_new_delete
>     : OPT_Wmismatched_dealloc);
> +  maybe_inform_function (loc, opt);
>  warned = warning_at (loc, opt,
>       "%qD called on pointer returned "
>       "from a mismatched allocation "
> @@ -3776,10 +3839,13 @@ pass_waccess::maybe_check_dealloc_call (gcall *call)
>  else if (gimple_call_builtin_p (def_stmt, BUILT_IN_ALLOCA)
>   || gimple_call_builtin_p (def_stmt,
>     BUILT_IN_ALLOCA_WITH_ALIGN))
> -    warned = warning_at (loc, OPT_Wfree_nonheap_object,
> +    {
> +      maybe_inform_function (loc, OPT_Wfree_nonheap_object);
> +      warned = warning_at (loc, OPT_Wfree_nonheap_object,
> "%qD called on pointer to "
> "an unallocated object",
> dealloc_decl);
> +    }
>  else if (warn_dealloc_offset (loc, call, aref))
>    return;
> 
> @@ -3923,6 +3989,7 @@ pass_waccess::warn_invalid_pointer (tree ref, gimple 
> *use_stmt,
>       const tree inval_decl = gimple_call_fndecl (inval_stmt);
> 
>       auto_diagnostic_group d;
> +      maybe_inform_function (use_loc, OPT_Wuse_after_free);
>       if ((ref && warning_at (use_loc, OPT_Wuse_after_free,
>      (maybe
>       ? G_("pointer %qE may be used after %qD")
> @@ -3949,6 +4016,7 @@ pass_waccess::warn_invalid_pointer (tree ref, gimple 
> *use_stmt,
>   if (DECL_NAME (var))
>     {
>       auto_diagnostic_group d;
> +      maybe_inform_function (use_loc, OPT_Wdangling_pointer_);
>       if ((ref
>   && warning_at (use_loc, OPT_Wdangling_pointer_,
>  (maybe
> @@ -3967,6 +4035,7 @@ pass_waccess::warn_invalid_pointer (tree ref, gimple 
> *use_stmt,
>       return;
>     }
> 
> +  maybe_inform_function (use_loc, OPT_Wdangling_pointer_);
>   if ((ref
>        && warning_at (use_loc, OPT_Wdangling_pointer_,
>      (maybe
> @@ -4073,6 +4142,7 @@ maybe_warn_mismatched_realloc (tree ptr, gimple 
> *realloc_stmt, gimple *stmt)
>   location_t loc = gimple_location (stmt);
>   tree realloc_decl = gimple_call_fndecl (realloc_stmt);
>   tree dealloc_decl = gimple_call_fndecl (stmt);
> +  maybe_inform_function (loc, OPT_Wmismatched_dealloc);
>   if (ptr && !warning_at (loc, OPT_Wmismatched_dealloc,
>  "%qD called on pointer %qE passed to mismatched "
>  "allocation function %qD",
> @@ -4603,6 +4673,7 @@ pass_waccess::check_dangling_stores (basic_block bb,
> 
>       auto_diagnostic_group d;
>       location_t loc = gimple_location (stmt);
> +      maybe_inform_function (loc, OPT_Wdangling_pointer_);
>       if (warning_at (loc, OPT_Wdangling_pointer_,
>      "storing the address of local variable %qD in %qE",
>      rhs_ref.ref, lhs))
> @@ -4750,6 +4821,7 @@ pass_waccess::check_call_dangling (gcall *call)
> unsigned
> pass_waccess::execute (function *fun)
> {
> +  printed_function = false;
>   calculate_dominance_info (CDI_DOMINATORS);
>   calculate_dominance_info (CDI_POST_DOMINATORS);
> 
> 
> 
> 
> -Andi

Reply via email to