Declaring a function with a prototype at block scope and then redeclaring it without a prototype at file scope results in losing the prototype but not the attribute access that was implicitly added to the function decl based on the prototype. The middle end code that checks function calls for out-of-bounds accesses based on the attribute is unprepared for this case and fails with an ICE. The attached patch corrects this by having it ignore these pathological cases. In addition, the change also improves the format of the informational note printed after these warnings to reflect the form of the argument (e.g., to print int[7] rather than int * if the former was the form used in the declaration).
Tested on x86_64-linux. Martin
Avoid pathological function redeclarations when checking access sizes [PR102759]. Resolves: PR tree-optimization/102759 - ICE: Segmentation fault in maybe_check_access_sizes since r12-2976-gb48d4e6818674898 PR tree-optimization/102759 gcc/ChangeLog: PR tree-optimization/102759 * gimple-array-bounds.cc (build_printable_array_type): Move... * gimple-ssa-warn-access.cc (build_printable_array_type): Avoid pathological function redeclarations that remove a previously declared prototype. Improve formatting of function arguments in informational notes. * pointer-query.cc (build_printable_array_type): ...to here. * pointer-query.h (build_printable_array_type): Declared. gcc/testsuite/ChangeLog: PR tree-optimization/102759 * gcc.dg/Warray-parameter-10.c: New test. * gcc.dg/Wstringop-overflow-82.c: New test. diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc index a3535598998..ddb99d263d1 100644 --- a/gcc/gimple-array-bounds.cc +++ b/gcc/gimple-array-bounds.cc @@ -372,31 +372,6 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, return warned; } -/* Wrapper around build_array_type_nelts that makes sure the array - can be created at all and handles zero sized arrays specially. */ - -static tree -build_printable_array_type (tree eltype, unsigned HOST_WIDE_INT nelts) -{ - if (TYPE_SIZE_UNIT (eltype) - && TREE_CODE (TYPE_SIZE_UNIT (eltype)) == INTEGER_CST - && !integer_zerop (TYPE_SIZE_UNIT (eltype)) - && TYPE_ALIGN_UNIT (eltype) > 1 - && wi::zext (wi::to_wide (TYPE_SIZE_UNIT (eltype)), - ffs_hwi (TYPE_ALIGN_UNIT (eltype)) - 1) != 0) - eltype = TYPE_MAIN_VARIANT (eltype); - - if (nelts) - return build_array_type_nelts (eltype, nelts); - - tree idxtype = build_range_type (sizetype, size_zero_node, NULL_TREE); - tree arrtype = build_array_type (eltype, idxtype); - arrtype = build_distinct_type_copy (TYPE_MAIN_VARIANT (arrtype)); - TYPE_SIZE (arrtype) = bitsize_zero_node; - TYPE_SIZE_UNIT (arrtype) = size_zero_node; - return arrtype; -} - /* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds references to string constants. If VRP can determine that the array subscript is a constant, check if it is outside valid range. diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 073f122af31..8248a5b38a1 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -2976,10 +2976,16 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, continue; tree ptrtype = fntype_argno_type (fntype, ptridx); + if (!ptrtype) + /* A function with a prototype was redeclared without one and + the protype has been lost. See pr102759. Avoid dealing + with this pathological case. */ + return; + tree argtype = TREE_TYPE (ptrtype); - /* The size of the access by the call. */ - tree access_size; + /* The size of the access by the call in elements. */ + tree access_nelts; if (sizidx == -1) { /* If only the pointer attribute operand was specified and @@ -2989,17 +2995,17 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, if the pointer is also declared with attribute nonnull. */ if (access.second.minsize && access.second.minsize != HOST_WIDE_INT_M1U) - access_size = build_int_cstu (sizetype, access.second.minsize); + access_nelts = build_int_cstu (sizetype, access.second.minsize); else - access_size = size_one_node; + access_nelts = size_one_node; } else - access_size = rwm->get (sizidx)->size; + access_nelts = rwm->get (sizidx)->size; /* Format the value or range to avoid an explosion of messages. */ char sizstr[80]; tree sizrng[2] = { size_zero_node, build_all_ones_cst (sizetype) }; - if (get_size_range (m_ptr_qry.rvals, access_size, stmt, sizrng, 1)) + if (get_size_range (m_ptr_qry.rvals, access_nelts, stmt, sizrng, 1)) { char *s0 = print_generic_expr_to_str (sizrng[0]); if (tree_int_cst_equal (sizrng[0], sizrng[1])) @@ -3057,6 +3063,8 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, } } + /* The size of the access by the call in bytes. */ + tree access_size = NULL_TREE; if (tree_int_cst_sgn (sizrng[0]) >= 0) { if (COMPLETE_TYPE_P (argtype)) @@ -3073,9 +3081,9 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, access_size = wide_int_to_tree (sizetype, minsize); } } + else + access_size = access_nelts; } - else - access_size = NULL_TREE; if (integer_zerop (ptr)) { @@ -3170,8 +3178,13 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, if (opt_warned != no_warning) { if (access.second.internal_p) - inform (loc, "referencing argument %u of type %qT", - ptridx + 1, ptrtype); + { + unsigned HOST_WIDE_INT nelts = + access_nelts ? access.second.minsize : HOST_WIDE_INT_M1U; + tree arrtype = build_printable_array_type (argtype, nelts); + inform (loc, "referencing argument %u of type %qT", + ptridx + 1, arrtype); + } else /* If check_access issued a warning above, append the relevant attribute to the string. */ diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index a0e4543d8a3..2ead0271617 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -2358,3 +2358,33 @@ array_elt_at_offset (tree artype, HOST_WIDE_INT off, return NULL_TREE; } + +/* Wrapper around build_array_type_nelts that makes sure the array + can be created at all and handles zero sized arrays specially. */ + +tree +build_printable_array_type (tree eltype, unsigned HOST_WIDE_INT nelts) +{ + if (TYPE_SIZE_UNIT (eltype) + && TREE_CODE (TYPE_SIZE_UNIT (eltype)) == INTEGER_CST + && !integer_zerop (TYPE_SIZE_UNIT (eltype)) + && TYPE_ALIGN_UNIT (eltype) > 1 + && wi::zext (wi::to_wide (TYPE_SIZE_UNIT (eltype)), + ffs_hwi (TYPE_ALIGN_UNIT (eltype)) - 1) != 0) + eltype = TYPE_MAIN_VARIANT (eltype); + + /* Consider excessive NELTS an array of unknown bound. */ + tree idxtype = NULL_TREE; + if (nelts < HOST_WIDE_INT_MAX) + { + if (nelts) + return build_array_type_nelts (eltype, nelts); + idxtype = build_range_type (sizetype, size_zero_node, NULL_TREE); + } + + tree arrtype = build_array_type (eltype, idxtype); + arrtype = build_distinct_type_copy (TYPE_MAIN_VARIANT (arrtype)); + TYPE_SIZE (arrtype) = bitsize_zero_node; + TYPE_SIZE_UNIT (arrtype) = size_zero_node; + return arrtype; +} diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h index c8215b681ef..fbea3316f14 100644 --- a/gcc/pointer-query.h +++ b/gcc/pointer-query.h @@ -275,4 +275,7 @@ extern tree array_elt_at_offset (tree, HOST_WIDE_INT, HOST_WIDE_INT * = nullptr, HOST_WIDE_INT * = nullptr); +/* Helper to build an array type that can be printed. */ +extern tree build_printable_array_type (tree, unsigned HOST_WIDE_INT); + #endif // GCC_POINTER_QUERY_H diff --git a/gcc/testsuite/gcc.dg/Warray-parameter-10.c b/gcc/testsuite/gcc.dg/Warray-parameter-10.c new file mode 100644 index 00000000000..378f8afbd34 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-parameter-10.c @@ -0,0 +1,20 @@ +/* PR c/102759 - ICE calling a function taking an argument redeclared + without a prototype. + { dg-do compile } + { dg-options "-Wall" } */ + +void f (void) +{ + void gia (int[2]); + void g (); +} + +/* Redeclaring the g(int[]) above without a prototype loses it. */ +void gia (); +void g (int[2]); + +void h (void ) +{ + gia (gia); + gia (g); +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-82.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-82.c new file mode 100644 index 00000000000..ee2693dcea9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-82.c @@ -0,0 +1,29 @@ +/* Verify that notes after warnings for array and VLA parameters show + the array form. + { dg-do compile } + { dg-options "-Wall" } */ + +void fia5 (int[5]); + +void gia3_fia5 (void) +{ + int a[3]; + fia5 (a); // { dg-warning "-Wstringop-overflow" } + // { dg-message "argument 1 of type 'int\\\[5]'" "note" { target *-*-* } .-1 } +} + + +/* The type of the argument would ideall be 'int[n]' but the variable + bound is lost/cleared by free-lang-data and never makes it into + the middle end. An (inferior) alternative would be 'int[*]' but + the pretty printer doesn't know how to format the star. A better + solution might be to introduce a new notation, like 'int[$1]', + where the $1 refers to the VLA argument bound. */ +void fvla (int n, int[n]); + +void gia3_fvla (void) +{ + int a[3]; + fvla (sizeof a, a); // { dg-warning "-Wstringop-overflow" } + // { dg-message "argument 2 of type 'int\\\[]'" "note" { target *-*-* } .-1 } +}