diff mbox series

Avoid pathological function redeclarations when checking access sizes [PR102759]

Message ID d88d1136-ad4c-7ae9-2fbf-a1f8ce316b0e@gmail.com
State New
Headers show
Series Avoid pathological function redeclarations when checking access sizes [PR102759] | expand

Commit Message

Martin Sebor Nov. 15, 2021, 8:31 p.m. UTC
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

Comments

Jeff Law Nov. 16, 2021, 2:23 a.m. UTC | #1
On 11/15/2021 1:31 PM, Martin Sebor via Gcc-patches wrote:
> 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
>
> gcc-102759.diff
>
> 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.
OK
jeff
diff mbox series

Patch

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 }
+}