Mercurial > hg > CbC > CbC_gcc
diff gcc/gimple-ssa-warn-alloca.c @ 132:d34655255c78
update gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 10:21:07 +0900 |
parents | 84e7813d76e9 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/gimple-ssa-warn-alloca.c Thu Oct 25 08:08:40 2018 +0900 +++ b/gcc/gimple-ssa-warn-alloca.c Thu Oct 25 10:21:07 2018 +0900 @@ -1,5 +1,5 @@ /* Warn on problematic uses of alloca and variable length arrays. - Copyright (C) 2016-2017 Free Software Foundation, Inc. + Copyright (C) 2016-2018 Free Software Foundation, Inc. Contributed by Aldy Hernandez <aldyh@redhat.com>. This file is part of GCC. @@ -33,10 +33,13 @@ #include "tree-ssa.h" #include "params.h" #include "tree-cfg.h" +#include "builtins.h" #include "calls.h" #include "cfgloop.h" #include "intl.h" +static unsigned HOST_WIDE_INT adjusted_warn_limit (bool); + const pass_data pass_data_walloca = { GIMPLE_PASS, "walloca", @@ -78,8 +81,12 @@ if (first_time_p) return warn_alloca != 0; - return ((unsigned HOST_WIDE_INT) warn_alloca_limit > 0 - || (unsigned HOST_WIDE_INT) warn_vla_limit > 0); + // Warning is disabled when its size limit is greater than PTRDIFF_MAX + // for the target maximum, which makes the limit negative since when + // represented in signed HOST_WIDE_INT. + unsigned HOST_WIDE_INT max = tree_to_uhwi (TYPE_MAX_VALUE (ptrdiff_type_node)); + return (adjusted_warn_limit (false) <= max + || adjusted_warn_limit (true) <= max); } // Possible problematic uses of alloca. @@ -121,9 +128,37 @@ alloca_type_and_limit (); alloca_type_and_limit (enum alloca_type type, wide_int i) : type(type), limit(i) { } - alloca_type_and_limit (enum alloca_type type) : type(type) { } + alloca_type_and_limit (enum alloca_type type) : type(type) + { if (type == ALLOCA_BOUND_MAYBE_LARGE + || type == ALLOCA_BOUND_DEFINITELY_LARGE) + limit = wi::to_wide (integer_zero_node); + } }; +/* Return the value of the argument N to -Walloca-larger-than= or + -Wvla-larger-than= adjusted for the target data model so that + when N == HOST_WIDE_INT_MAX, the adjusted value is set to + PTRDIFF_MAX on the target. This is done to prevent warnings + for unknown/unbounded allocations in the "permissive mode" + while still diagnosing excessive and necessarily invalid + allocations. */ + +static unsigned HOST_WIDE_INT +adjusted_warn_limit (bool idx) +{ + static HOST_WIDE_INT limits[2]; + if (limits[idx]) + return limits[idx]; + + limits[idx] = idx ? warn_vla_limit : warn_alloca_limit; + if (limits[idx] != HOST_WIDE_INT_MAX) + return limits[idx]; + + limits[idx] = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node)); + return limits[idx]; +} + + // NOTE: When we get better range info, this entire function becomes // irrelevant, as it should be possible to get range info for an SSA // name at any point in the program. @@ -150,13 +185,25 @@ // in bytes we allow for arg. static struct alloca_type_and_limit -alloca_call_type_by_arg (tree arg, tree arg_casted, edge e, unsigned max_size) +alloca_call_type_by_arg (tree arg, tree arg_casted, edge e, + unsigned HOST_WIDE_INT max_size) { basic_block bb = e->src; gimple_stmt_iterator gsi = gsi_last_bb (bb); gimple *last = gsi_stmt (gsi); + + const offset_int maxobjsize = tree_to_shwi (max_object_size ()); + + /* When MAX_SIZE is greater than or equal to PTRDIFF_MAX treat + allocations that aren't visibly constrained as OK, otherwise + report them as (potentially) unbounded. */ + alloca_type unbounded_result = (max_size < maxobjsize.to_uhwi () + ? ALLOCA_UNBOUNDED : ALLOCA_OK); + if (!last || gimple_code (last) != GIMPLE_COND) - return alloca_type_and_limit (ALLOCA_UNBOUNDED); + { + return alloca_type_and_limit (unbounded_result); + } enum tree_code cond_code = gimple_cond_code (last); if (e->flags & EDGE_TRUE_VALUE) @@ -164,7 +211,7 @@ else if (e->flags & EDGE_FALSE_VALUE) cond_code = invert_tree_comparison (cond_code, false); else - return alloca_type_and_limit (ALLOCA_UNBOUNDED); + return alloca_type_and_limit (unbounded_result); // Check for: // if (ARG .COND. N) @@ -199,7 +246,15 @@ } } else - return alloca_type_and_limit (ALLOCA_BOUND_UNKNOWN); + { + /* Analogous to ALLOCA_UNBOUNDED, when MAX_SIZE is greater + than or equal to PTRDIFF_MAX, treat allocations with + an unknown bound as OK. */ + alloca_type unknown_result + = (max_size < maxobjsize.to_uhwi () + ? ALLOCA_BOUND_UNKNOWN : ALLOCA_OK); + return alloca_type_and_limit (unknown_result); + } } // Similarly, but check for a comparison with an unknown LIMIT. @@ -217,7 +272,7 @@ && TREE_CODE (limit) == SSA_NAME) { wide_int min, max; - value_range_type range_type = get_range_info (limit, &min, &max); + value_range_kind range_type = get_range_info (limit, &min, &max); if (range_type == VR_UNDEFINED || range_type == VR_VARYING) return alloca_type_and_limit (ALLOCA_BOUND_UNKNOWN); @@ -229,10 +284,10 @@ // // If this ever triggers, we should probably figure out why and // handle it, though it is likely to be just an ALLOCA_UNBOUNDED. - return alloca_type_and_limit (ALLOCA_UNBOUNDED); + return alloca_type_and_limit (unbounded_result); } - return alloca_type_and_limit (ALLOCA_UNBOUNDED); + return alloca_type_and_limit (unbounded_result); } // Return TRUE if SSA's definition is a cast from a signed type. @@ -281,16 +336,12 @@ edge_iterator ei; edge e; - gcc_assert (!is_vla || (unsigned HOST_WIDE_INT) warn_vla_limit > 0); - gcc_assert (is_vla || (unsigned HOST_WIDE_INT) warn_alloca_limit > 0); + gcc_assert (!is_vla || warn_vla_limit >= 0); + gcc_assert (is_vla || warn_alloca_limit >= 0); // Adjust warn_alloca_max_size for VLAs, by taking the underlying // type into account. - unsigned HOST_WIDE_INT max_size; - if (is_vla) - max_size = (unsigned HOST_WIDE_INT) warn_vla_limit; - else - max_size = (unsigned HOST_WIDE_INT) warn_alloca_limit; + unsigned HOST_WIDE_INT max_size = adjusted_warn_limit (is_vla); // Check for the obviously bounded case. if (TREE_CODE (len) == INTEGER_CST) @@ -299,7 +350,13 @@ return alloca_type_and_limit (ALLOCA_BOUND_DEFINITELY_LARGE, wi::to_wide (len)); if (integer_zerop (len)) - return alloca_type_and_limit (ALLOCA_ARG_IS_ZERO); + { + const offset_int maxobjsize + = wi::to_offset (max_object_size ()); + alloca_type result = (max_size < maxobjsize + ? ALLOCA_ARG_IS_ZERO : ALLOCA_OK); + return alloca_type_and_limit (result); + } return alloca_type_and_limit (ALLOCA_OK); } @@ -307,7 +364,7 @@ // Check the range info if available. if (TREE_CODE (len) == SSA_NAME) { - value_range_type range_type = get_range_info (len, &min, &max); + value_range_kind range_type = get_range_info (len, &min, &max); if (range_type == VR_RANGE) { if (wi::leu_p (max, max_size)) @@ -357,8 +414,15 @@ } else if (range_type == VR_ANTI_RANGE) return alloca_type_and_limit (ALLOCA_UNBOUNDED); - else if (range_type != VR_VARYING) - return alloca_type_and_limit (ALLOCA_BOUND_MAYBE_LARGE, max); + + if (range_type != VR_VARYING) + { + const offset_int maxobjsize + = wi::to_offset (max_object_size ()); + alloca_type result = (max_size < maxobjsize + ? ALLOCA_BOUND_MAYBE_LARGE : ALLOCA_OK); + return alloca_type_and_limit (result, max); + } } } else if (range_type == VR_ANTI_RANGE) @@ -414,8 +478,13 @@ if (compare_tree_int (arg, max_size) <= 0) ret = alloca_type_and_limit (ALLOCA_OK); else - ret = alloca_type_and_limit (ALLOCA_BOUND_MAYBE_LARGE, - wi::to_wide (arg)); + { + const offset_int maxobjsize + = wi::to_offset (max_object_size ()); + alloca_type result = (max_size < maxobjsize + ? ALLOCA_BOUND_MAYBE_LARGE : ALLOCA_OK); + ret = alloca_type_and_limit (result, wi::to_wide (arg)); + } } return ret; @@ -445,7 +514,6 @@ if (!gimple_alloca_call_p (stmt)) continue; - gcc_assert (gimple_call_num_args (stmt) >= 1); const bool is_vla = gimple_call_alloca_for_var_p (as_a <gcall *> (stmt)); @@ -453,26 +521,37 @@ // Strict mode whining for VLAs is handled by the front-end, // so we can safely ignore this case. Also, ignore VLAs if // the user doesn't care about them. - if (is_vla - && (warn_vla > 0 || !warn_vla_limit)) - continue; - - if (!is_vla && (warn_alloca || !warn_alloca_limit)) + if (is_vla) { - if (warn_alloca) - warning_at (loc, OPT_Walloca, G_("use of %<alloca%>")); + if (warn_vla > 0 || warn_vla_limit < 0) + continue; + } + else if (warn_alloca) + { + warning_at (loc, OPT_Walloca, G_("use of %<alloca%>")); continue; } + else if (warn_alloca_limit < 0) + continue; tree invalid_casted_type = NULL; struct alloca_type_and_limit t = alloca_call_type (stmt, is_vla, &invalid_casted_type); + unsigned HOST_WIDE_INT adjusted_alloca_limit + = adjusted_warn_limit (false); // Even if we think the alloca call is OK, make sure it's not in a // loop, except for a VLA, since VLAs are guaranteed to be cleaned // up when they go out of scope, including in a loop. if (t.type == ALLOCA_OK && !is_vla && in_loop_p (stmt)) - t = alloca_type_and_limit (ALLOCA_IN_LOOP); + { + /* As in other instances, only diagnose this when the limit + is less than the maximum valid object size. */ + const offset_int maxobjsize + = wi::to_offset (max_object_size ()); + if (adjusted_alloca_limit < maxobjsize.to_uhwi ()) + t = alloca_type_and_limit (ALLOCA_IN_LOOP); + } enum opt_code wcode = is_vla ? OPT_Wvla_larger_than_ : OPT_Walloca_larger_than_; @@ -482,29 +561,38 @@ case ALLOCA_OK: break; case ALLOCA_BOUND_MAYBE_LARGE: - if (warning_at (loc, wcode, - is_vla ? G_("argument to variable-length array " - "may be too large") - : G_("argument to %<alloca%> may be too large")) - && t.limit != 0) - { - print_decu (t.limit, buff); - inform (loc, G_("limit is %u bytes, but argument " - "may be as large as %s"), - is_vla ? warn_vla_limit : warn_alloca_limit, buff); - } + { + auto_diagnostic_group d; + if (warning_at (loc, wcode, + is_vla ? G_("argument to variable-length " + "array may be too large") + : G_("argument to %<alloca%> may be too " + "large")) + && t.limit != 0) + { + print_decu (t.limit, buff); + inform (loc, G_("limit is %wu bytes, but argument " + "may be as large as %s"), + is_vla ? warn_vla_limit : adjusted_alloca_limit, + buff); + } + } break; case ALLOCA_BOUND_DEFINITELY_LARGE: - if (warning_at (loc, wcode, - is_vla ? G_("argument to variable-length array " - "is too large") - : G_("argument to %<alloca%> is too large")) - && t.limit != 0) - { - print_decu (t.limit, buff); - inform (loc, G_("limit is %u bytes, but argument is %s"), - is_vla ? warn_vla_limit : warn_alloca_limit, buff); - } + { + auto_diagnostic_group d; + if (warning_at (loc, wcode, + is_vla ? G_("argument to variable-length" + " array is too large") + : G_("argument to %<alloca%> is too large")) + && t.limit != 0) + { + print_decu (t.limit, buff); + inform (loc, G_("limit is %wu bytes, but argument is %s"), + is_vla ? warn_vla_limit : adjusted_alloca_limit, + buff); + } + } break; case ALLOCA_BOUND_UNKNOWN: warning_at (loc, wcode,