diff mbox series

avoid an other ICE due to invalid built-in call (PR 89934)

Message ID 1fe3da88-eb66-c8aa-87b3-4680a56e8c08@gmail.com
State New
Headers show
Series avoid an other ICE due to invalid built-in call (PR 89934) | expand

Commit Message

Martin Sebor April 3, 2019, 7:27 p.m. UTC
PR 89934 reports yet another ICE due to a call to a library
built-in function with invalid arguments.  The attached patch
does the bare minimum to avoid it.  I will commit it to trunk
and to GCC 8 later this week if there are no objections.

Martin

PS There have been many of these reports (at least three in
the wrestrict pass alone, and quite a few elsewhere).  Simply
avoiding the ICEs as this patch does and as all the others
before it have done as well does nothing to help solve
the underlying problem in user code: the invalid calls will
end up with undefined behavior if they are ever made at runtime.
For example, the one in this bug report will most likely cause
data corruption or buffer overflow without ever being detected
by _FORTIFY_SOURCE.  That seems far worse than failing to compile
the code (either with an ICE or with some
other hard error).

For GCC 10 I think a more robust solution should be put in place
not just to prevent these invalid built-in calls from tripping
up the middle-end, but also to avoid the undefined behavior at
runtime.  The calls could either be rejected with an error as
Clang does, or they could be replaced them with __builtin_trap
or perhaps __builtin_unreachable, depending on some command
line option.

Comments

Jeff Law April 4, 2019, 9:11 p.m. UTC | #1
On 4/3/19 1:27 PM, Martin Sebor wrote:
> PR 89934 reports yet another ICE due to a call to a library
> built-in function with invalid arguments.  The attached patch
> does the bare minimum to avoid it.  I will commit it to trunk
> and to GCC 8 later this week if there are no objections.
> 
> Martin
> 
> PS There have been many of these reports (at least three in
> the wrestrict pass alone, and quite a few elsewhere).  Simply
> avoiding the ICEs as this patch does and as all the others
> before it have done as well does nothing to help solve
> the underlying problem in user code: the invalid calls will
> end up with undefined behavior if they are ever made at runtime.
> For example, the one in this bug report will most likely cause
> data corruption or buffer overflow without ever being detected
> by _FORTIFY_SOURCE.  That seems far worse than failing to compile
> the code (either with an ICE or with some
> other hard error).
> 
> For GCC 10 I think a more robust solution should be put in place
> not just to prevent these invalid built-in calls from tripping
> up the middle-end, but also to avoid the undefined behavior at
> runtime.  The calls could either be rejected with an error as
> Clang does, or they could be replaced them with __builtin_trap
> or perhaps __builtin_unreachable, depending on some command
> line option.
> 
> 
> gcc-89934.diff
> 
> PR middle-end/89934 - ICE on a call with fewer arguments to strncpy declared without prototype
> 
> gcc/ChangeLog:
> 
> 	PR middle-end/89934
> 	* gimple-ssa-warn-restrict.c (builtin_access::builtin_access): Bail
> 	out if the number of arguments is less than expected.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR middle-end/89934
> 	* gcc.dg/Wrestrict-19.c: New test.
> 	* gcc.dg/Wrestrict-5.c: Add comment.  Remove unused code.
OK.

WRT the larger issue.  Assume we have the infrastructure bits to
transform the bogus calls into a __builtin_trap or __builtin_unreachable
(which I think we can easily lift from elsewhere) and a flag to allow us
to determine which style we want. (we can build and prototype that and
use the result in the erroneous-path-isolation pass).

The question is when do we want to detect the bogus calls.  There are
some that we'd likely want to catch early, such as the wrong number of
arguments like we see in this case.  That feels like a pass over the IL
right after gimplification.

Other cases are more interesting.  Do we try to detect when a
propagation makes the call invalid as soon as it happens, or do we defer
to the erroneous path isolation pass?    Or do we end up doing both as
there may be cases where analysis is nontrivial.  Anyway, I think we can
start working down this path for gcc-10.

jeff
diff mbox series

Patch

PR middle-end/89934 - ICE on a call with fewer arguments to strncpy declared without prototype

gcc/ChangeLog:

	PR middle-end/89934
	* gimple-ssa-warn-restrict.c (builtin_access::builtin_access): Bail
	out if the number of arguments is less than expected.

gcc/testsuite/ChangeLog:

	PR middle-end/89934
	* gcc.dg/Wrestrict-19.c: New test.
	* gcc.dg/Wrestrict-5.c: Add comment.  Remove unused code.

Index: gcc/gimple-ssa-warn-restrict.c
===================================================================
--- gcc/gimple-ssa-warn-restrict.c	(revision 270061)
+++ gcc/gimple-ssa-warn-restrict.c	(working copy)
@@ -730,6 +730,10 @@  builtin_access::builtin_access (gimple *call, buil
   offset_int bounds[2] = { maxobjsize, maxobjsize };
   if (dstref->strbounded_p)
     {
+      unsigned nargs = gimple_call_num_args (call);
+      if (nargs <= sizeargno)
+	return;
+
       tree size = gimple_call_arg (call, sizeargno);
       tree range[2];
       if (get_size_range (size, range, true))
Index: gcc/testsuite/gcc.dg/Wrestrict-19.c
===================================================================
--- gcc/testsuite/gcc.dg/Wrestrict-19.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/Wrestrict-19.c	(working copy)
@@ -0,0 +1,33 @@ 
+/* PR middle-end/89934 - ICE on a call with fewer arguments to strncpy
+   declared without prototype
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+char *strncpy ();
+
+char* f0 (char *s)
+{
+  return strncpy ();
+}
+
+char* f1 (char *s)
+{
+  return strncpy (s);
+}
+
+char* f2 (char *s)
+{
+  return strncpy (s, s + 1);   /* ICE here.  */
+}
+
+void f3 (char *s, size_t n, const char *t)
+{
+  strncpy (s, n, t);
+  strncpy (n, s, t);
+}
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" }
+   { dg-prune-output "\\\[-Wint-conversion]" } */
+
Index: gcc/testsuite/gcc.dg/Wrestrict-5.c
===================================================================
--- gcc/testsuite/gcc.dg/Wrestrict-5.c	(revision 270061)
+++ gcc/testsuite/gcc.dg/Wrestrict-5.c	(working copy)
@@ -1,20 +1,11 @@ 
-/* Test to verify that valid calls to common restrict-qualified built-in
+/* PR tree-optimization/83655 - ICE on an invalid call to memcpy declared
+   with no prototype
+   Test to verify that valid calls to common restrict-qualified built-in
    functions declared with no prototype are checked for overlap, and that
    invalid calls are ignored.
   { dg-do compile }
-  { dg-prune-output "conflicting types for built-in" }
   { dg-options "-O2 -Wrestrict" }  */
 
-typedef __SIZE_TYPE__ size_t;
-
-#if __cplusplus
-extern "C" {
-
-#define NO_PROTO ...
-#else
-#define NO_PROTO /* empty */
-#endif
-
 void* memcpy ();
 char* strncpy ();