This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC PATCH] Automatically check reproducability of ICE (if possible) and prepare testcase if reproducible


Hi!

We are using following patch in Red Hat GCC packages for a while to make
things easier both for bugreporters reporting ICEs and those who deal with
the bugs.
The patch changes the compiler to exit with a magic exit code if an ICE
happened (different from FATAL_EXIT_CODE).  The gcc driver, if it sees
an ICE, attempts to reproduce it 3 times if possible (this is not possible
e.g. if source is on gcc's standard input etc.) and if the bug is
reproduceable (dies with ICE in all cases and issues the same error
messages), prepares a preprocessed testcase in a temporary file and tells
the user where it is.  The preprocessed testcase is preceeded by 
the command line used to reproduce it on its first line (as comment).
On the other side, if it cannot reproduce the bug, it tells the user
about possible hardware problems or kernel issues.
It saved me already quite some time when dealing with bug reports.

Would anything like this be acceptable for CVS GCC or shall I keep it
as a local hack?

2004-01-23  Jakub Jelinek  <jakub@redhat.com>

	* system.h (ICE_EXIT_CODE): Define.
	* gcc.c (execute): Don't free first string early, but at the end
	of the function.  Call retry_ice if compiler exited with
	ICE_EXIT_CODE.
	(retry_ice): New function.
	* diagnostic.c (diagnostic_count_diagnostic,
	diagnostic_action_after_output, error_recursion): Exit with
	ICE_EXIT_CODE instead of FATAL_EXIT_CODE.

--- gcc/system.h.jj	2004-01-19 17:29:30.000000000 +0100
+++ gcc/system.h	2004-01-21 11:53:41.000000000 +0100
@@ -153,6 +153,10 @@ extern int errno;
 # endif
 #endif
 
+#ifndef ICE_EXIT_CODE
+# define ICE_EXIT_CODE 27
+#endif
+
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
--- gcc/gcc.c.jj	2004-01-21 11:45:20.000000000 +0100
+++ gcc/gcc.c	2004-01-21 11:56:46.000000000 +0100
@@ -352,6 +352,9 @@ static void init_gcc_specs (struct obsta
 #if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
 static const char *convert_filename (const char *, int, int);
 #endif
+#if !(defined (__MSDOS__) || defined (OS2) || defined (VMS))
+static void retry_ice (const char *prog, const char **argv);
+#endif
 
 static const char *if_exists_spec_function (int, const char **);
 static const char *if_exists_else_spec_function (int, const char **);
@@ -2753,7 +2756,7 @@ execute (void)
       if (commands[i].pid == -1)
 	pfatal_pexecute (errmsg_fmt, errmsg_arg);
 
-      if (string != commands[i].prog)
+      if (i && string != commands[i].prog)
 	free ((void *) string);
     }
 
@@ -2831,6 +2834,17 @@ See %s for instructions.",
 	      else if (WIFEXITED (status)
 		       && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
 		{
+#if !(defined (__MSDOS__) || defined (OS2) || defined (VMS))
+		  /* For ICEs in cc1, cc1obj, cc1plus see if it is
+		     reproduceable or not.  */
+		  char *p;
+		  if (WEXITSTATUS (status) == ICE_EXIT_CODE
+		      && j == 0
+		      && (p = strrchr (commands[j].argv[0], DIR_SEPARATOR))
+		      && ! strncmp (p + 1, "cc1", 3))
+		    retry_ice (commands[j].prog, commands[j].argv);
+#endif
+
 		  if (WEXITSTATUS (status) > greatest_status)
 		    greatest_status = WEXITSTATUS (status);
 		  ret_code = -1;
@@ -2842,6 +2856,10 @@ See %s for instructions.",
 	      break;
 	    }
       }
+
+    if (commands[0].argv[0] != commands[0].prog)
+      free ((PTR) commands[0].argv[0]);
+
     return ret_code;
   }
 }
@@ -5809,6 +5827,222 @@ give_switch (int switchnum, int omit_fir
   switches[switchnum].validated = 1;
 }
 
+#if !(defined (__MSDOS__) || defined (OS2) || defined (VMS))
+#define RETRY_ICE_ATTEMPTS 2
+
+static void
+retry_ice (const char *prog, const char **argv)
+{
+  int nargs, out_arg = -1, quiet = 0, attempt;
+  int pid, retries, sleep_interval;
+  const char **new_argv;
+  char *temp_filenames[RETRY_ICE_ATTEMPTS * 2 + 2];
+
+  if (input_filename == NULL || ! strcmp (input_filename, "-"))
+    return;
+
+  for (nargs = 0; argv[nargs] != NULL; ++nargs)
+    /* Only retry compiler ICEs, not preprocessor ones.  */
+    if (! strcmp (argv[nargs], "-E"))
+      return;
+    else if (argv[nargs][0] == '-' && argv[nargs][1] == 'o')
+      {
+	if (out_arg == -1)
+	  out_arg = nargs;
+	else
+	  return;
+      }
+    /* If the compiler is going to output any time information,
+       it might varry between invocations.  */
+    else if (! strcmp (argv[nargs], "-quiet"))
+      quiet = 1;
+    else if (! strcmp (argv[nargs], "-ftime-report"))
+      return;
+
+  if (out_arg == -1 || !quiet)
+    return;
+
+  memset (temp_filenames, '\0', sizeof (temp_filenames));
+  new_argv = alloca ((nargs + 2) * sizeof (const char *));
+  memcpy (new_argv, argv, (nargs + 1) * sizeof (const char *));
+  if (new_argv[out_arg][2] == '\0')
+    new_argv[out_arg + 1] = "-";
+  else
+    new_argv[out_arg] = "-o-";
+
+  for (attempt = 0; attempt < RETRY_ICE_ATTEMPTS + 1; ++attempt)
+    {
+      int fd;
+      int status;
+
+      temp_filenames[attempt * 2] = make_temp_file (".out");
+      temp_filenames[attempt * 2 + 1] = make_temp_file (".err");
+
+      if (attempt == RETRY_ICE_ATTEMPTS)
+        {
+	  int i;
+	  int fd1, fd2;
+	  struct stat st1, st2;
+	  size_t n, len;
+	  char *buf;
+
+	  buf = xmalloc (8192);
+
+	  for (i = 0; i < 2; ++i)
+	    {
+	      fd1 = open (temp_filenames[i], O_RDONLY);
+	      fd2 = open (temp_filenames[2 + i], O_RDONLY);
+
+	      if (fd1 < 0 || fd2 < 0)
+		{
+		  i = -1;
+		  close (fd1);
+		  close (fd2);
+		  break;
+		}
+
+	      if (fstat (fd1, &st1) < 0 || fstat (fd2, &st2) < 0)
+		{
+		  i = -1;
+		  close (fd1);
+		  close (fd2);
+		  break;
+		}
+
+	      if (st1.st_size != st2.st_size)
+		{
+		  close (fd1);
+		  close (fd2);
+		  break;
+		}
+
+	      len = 0;
+	      for (n = st1.st_size; n; n -= len)
+		{
+		  len = n;
+		  if (len > 4096)
+		    len = 4096;
+
+		  if (read (fd1, buf, len) != (int) len
+		      || read (fd2, buf + 4096, len) != (int) len)
+		    {
+		      i = -1;
+		      break;
+		    }
+
+		  if (memcmp (buf, buf + 4096, len) != 0)
+		    break;
+		}
+
+	      close (fd1);
+	      close (fd2);
+
+	      if (n)
+		break;
+	    }
+
+	  free (buf);
+	  if (i == -1)
+	    break;
+
+	  if (i != 2)
+	    {
+	      notice ("The bug is not reproduceable, so it is likely a hardware or OS problem\n");
+	      break;
+	    }
+
+          fd = open (temp_filenames[attempt * 2], O_RDWR);
+	  if (fd < 0)
+	    break;
+	  write (fd, "//", 2);
+	  for (i = 0; i < nargs; i++)
+	    {
+	      write (fd, " ", 1);
+	      write (fd, new_argv[i], strlen (new_argv[i]));
+	    }
+	  write (fd, "\n", 1);
+	  new_argv[nargs] = "-E";
+	  new_argv[nargs + 1] = NULL;
+        }
+
+      /* Fork a subprocess; wait and retry if it fails.  */
+      sleep_interval = 1;
+      pid = -1;
+      for (retries = 0; retries < 4; retries++)
+	{
+	  pid = fork ();
+	  if (pid >= 0)
+	    break;
+	  sleep (sleep_interval);
+	  sleep_interval *= 2;
+	}
+
+      if (pid < 0)
+	break;
+      else if (pid == 0)
+	{
+	  if (attempt != RETRY_ICE_ATTEMPTS)
+	    fd = open (temp_filenames[attempt * 2], O_RDWR);
+	  if (fd < 0)
+	    exit (-1);
+	  if (fd != 1)
+	    {
+	      close (1);
+	      dup (fd);
+	      close (fd);
+	    }
+
+	  fd = open (temp_filenames[attempt * 2 + 1], O_RDWR);
+	  if (fd < 0)
+	    exit (-1);
+	  if (fd != 2)
+	    {
+	      close (2);
+	      dup (fd);
+	      close (fd);
+	    }
+
+	  if (prog == new_argv[0])
+	    execvp (prog, (char *const *) new_argv);
+	  else
+	    execv (new_argv[0], (char *const *) new_argv);
+	  exit (-1);
+	}
+
+      if (waitpid (pid, &status, 0) < 0)
+	break;
+
+      if (attempt < RETRY_ICE_ATTEMPTS
+	  && (! WIFEXITED (status) || WEXITSTATUS (status) != ICE_EXIT_CODE))
+	{
+	  notice ("The bug is not reproduceable, so it is likely a hardware or OS problem\n");
+	  break;
+	}
+      else if (attempt == RETRY_ICE_ATTEMPTS)
+	{
+	  close (fd);
+	  if (WIFEXITED (status)
+	      && WEXITSTATUS (status) == SUCCESS_EXIT_CODE)
+	    {
+	      notice ("Preprocessed source stored into %s file, please attach this to your bugreport\n",
+		      temp_filenames[attempt * 2]);
+	      /* Make sure it is not deleted.  */
+	      free (temp_filenames[attempt * 2]);
+	      temp_filenames[attempt * 2] = NULL;
+	      break;
+	    }
+	}
+    }
+
+  for (attempt = 0; attempt < RETRY_ICE_ATTEMPTS * 2 + 2; attempt++)
+    if (temp_filenames[attempt])
+      {
+	unlink (temp_filenames[attempt]);
+	free (temp_filenames[attempt]);
+      }
+}
+#endif
+
 /* Search for a file named NAME trying various prefixes including the
    user's -B prefix and some standard ones.
    Return the absolute file name found.  If nothing is found, return NAME.  */
--- gcc/diagnostic.c.jj	2003-10-01 12:09:21.000000000 +0200
+++ gcc/diagnostic.c	2004-01-21 11:54:47.000000000 +0100
@@ -208,7 +208,7 @@ diagnostic_count_diagnostic (diagnostic_
 	{
 	  fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n",
 		   diagnostic->location.file, diagnostic->location.line);
-	  exit (FATAL_EXIT_CODE);
+	  exit (ICE_EXIT_CODE);
 	}
 #endif
       if (context->internal_error)
@@ -272,14 +272,14 @@ diagnostic_action_after_output (diagnost
 	real_abort ();
 
       fnotice (stderr, bug_report_request, bug_report_url);
-      exit (FATAL_EXIT_CODE);
+      exit (ICE_EXIT_CODE);
 
     case DK_FATAL:
       if (context->abort_on_error)
 	real_abort ();
 
       fnotice (stderr, "compilation terminated.\n");
-      exit (FATAL_EXIT_CODE);
+      exit (ICE_EXIT_CODE);
 
     default:
       real_abort ();
@@ -571,7 +571,7 @@ error_recursion (diagnostic_context *con
   fnotice (stderr,
 	   "Internal compiler error: Error reporting routines re-entered.\n");
   fnotice (stderr, bug_report_request, bug_report_url);
-  exit (FATAL_EXIT_CODE);
+  exit (ICE_EXIT_CODE);
 }
 
 /* Report an internal compiler error in a friendly manner.  This is

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]