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