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. 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