[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: confusing message in Debian gcc "bug is not reproducible, so it is likely a hardware or OS problem"



On Mon, Sep 24, 2012 at 04:35:54PM +0200, Matthias Klose wrote:
> On 24.09.2012 16:24, Basile Starynkevitch wrote:
> > On Mon, Sep 24, 2012 at 03:14:42PM +0200, Jakub Jelinek wrote:
> >> On Mon, Sep 24, 2012 at 02:10:50PM +0200, Basile Starynkevitch wrote:
> >>> Ok, to say it in other words:
> >>>
> >>>    experimentally, a plugin which calls fatal_error (and this is definitely an
> >>>    acceptable behavior for plugins) makes Debian GCC output the original message,
> >>>    which is very confusing since the error is really called by a plugin.
> >>>    I have no idea if a plugin problem is considered or not as a non reproducible bug.
> >>>    But certainly, a fatal_error from a plugin's pass should not make GCC gives a
> >>>    message which suggest hardware issues, while it is simply due to some plugin.
> >>>
> >>> It would be very nice if the error message contained the "plugin" word (at least
> >>> when some plugin is used).
> >>
> >> You should get that message only if the problem is not reproduceable, i.e.
> >> the exit code, stdout or stderr of the compiler is different between the
> >> several invocations the driver retries.  So, the plugin would need to emit
> >> different errors or exit code in each case.  Is your plugin that broken?
> > 
> > Could you explain a bit more what are the conditions to get that message? 
> > What source file (of what Debian patch of GCC) is producing that?
> 
> debian/patches/gcc-ice-hack.diff

I really believe that a GCC plugin may have non-deterministic (or simply, 
difficult to reproduce) behavior, and still be valid (imagine a plugin producing a
unique serial number, or a plugin querying some remote database or web service).
So I believe that at least for plugins, GCC should not automagically restart,
and when it does restart, it should say so.

And MELT's behavior is non deterministic, e.g. because it is itself forking a make
(since MELT plugin is generating C code, compiling it by make, then dlopen-ing it, all from 
the same 'cc1 -fplugin=melt' process), because it is using randomly generated hash codes
(random being by default seeded thru time(2) or /dev/random), etc. I don't expect MELT failures
to be exactly the same.

I am attaching a slightly improved version of gcc-ice-hack.diff

Could you suggest me a way of detecting if a vendor GCC has this patch.
I was thinking of something like

if [ strings $(which gcc) | grep -q 'bug is not reproducible, so it is likely a hardware or OS' ]; then
   ### do something
fi

Regards.
-- 
Basile STARYNKEVITCH         http://starynkevitch.net/Basile/
email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359
8, rue de la Faiencerie, 92340 Bourg La Reine, France
*** opinions {are only mines, sont seulement les miennes} ***
# DP: Retry the build on an ice, save the calling options and preprocessed
# DP: source when the ice is reproducible.

2012-09-24  Basile Starynkevitch  <basile@starynkevitch.net>

	* gcc (retry_ice): Don't retry for plugins. Retry verbosely.

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

	* 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.

#--- a/src/gcc/Makefile.in
#+++ b/src/gcc/Makefile.in
#@@ -181,6 +181,8 @@ SYSCALLS.c.X-warn = -Wno-strict-prototypes -Wno-error
# dfp.o-warn = -Wno-error
# # mips-tfile.c contains -Wcast-qual warnings.
# mips-tfile.o-warn = -Wno-error
#+# gcc-ice-hack
#+gcc.o-warn = -Wno-error
# 
# # All warnings have to be shut off in stage1 if the compiler used then
# # isn't gcc; configure determines that.  WARN_CFLAGS will be either
--- a/src/gcc/gcc.c
+++ b/src/gcc/gcc.c
@@ -250,6 +250,9 @@
 #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 *getenv_spec_function (int, const char **);
 static const char *if_exists_spec_function (int, const char **);
@@ -2638,7 +2643,7 @@
 	    }
 	}
 
-      if (string != commands[i].prog)
+      if (i && string != commands[i].prog)
 	free (CONST_CAST (char *, string));
     }
 
@@ -2691,6 +2696,16 @@
 	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
+	       reproducible or not.  */
+	    const char *p;
+	    if (WEXITSTATUS (status) == ICE_EXIT_CODE
+		&& i == 0
+		&& (p = strrchr (commands[0].argv[0], DIR_SEPARATOR))
+		&& ! strncmp (p + 1, "cc1", 3))
+	      retry_ice (commands[0].prog, commands[0].argv);
+#endif
 	    if (WEXITSTATUS (status) > greatest_status)
 	      greatest_status = WEXITSTATUS (status);
 	    ret_code = -1;
@@ -2748,6 +2763,9 @@
 	  }
       }
 
+    if (commands[0].argv[0] != commands[0].prog)
+      free (CONST_CAST (char *, commands[0].argv[0]));
+
     return ret_code;
   }
 }
@@ -5874,6 +5892,227 @@
   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 (gcc_input_filename == NULL || ! strcmp (gcc_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;
+    else if (! strncmp (argv[nargs], "-fplugin", 8))
+      return;
+
+  if (out_arg == -1 || !quiet)
+    return;
+
+  memset (temp_filenames, '\0', sizeof (temp_filenames));
+  new_argv = XALLOCAVEC (const char *, nargs + 3);
+  memcpy (new_argv, argv, (nargs + 1) * sizeof (const char *));
+  new_argv[nargs++] = "-frandom-seed=0";
+  new_argv[nargs] = NULL;
+  if (new_argv[out_arg][2] == '\0')
+    new_argv[out_arg + 1] = "-";
+  else
+    new_argv[out_arg] = "-o-";
+
+  fnotice (stderr, 
+           "Auto-magically retrying GCC %d times after compiler error.\n",
+            RETRY_ICE_ATTEMPTS);
+  for (attempt = 0; attempt < RETRY_ICE_ATTEMPTS + 1; ++attempt)
+    {
+      int fd = -1;
+      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 = XNEWVEC (char, 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)
+	    {
+	      fnotice (stderr, "The bug is not reproducible, 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, CONST_CAST2 (char *const *, const char **, new_argv));
+	  else
+	    execv (new_argv[0], CONST_CAST2 (char *const *, const char **, new_argv));
+	  exit (-1);
+	}
+
+      if (waitpid (pid, &status, 0) < 0)
+	break;
+
+      if (attempt < RETRY_ICE_ATTEMPTS
+	  && (! WIFEXITED (status) || WEXITSTATUS (status) != ICE_EXIT_CODE))
+	{
+	  fnotice (stderr, "The bug is not reproducible, 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)
+	    {
+	      fnotice (stderr, "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.  */
--- a/src/gcc/diagnostic.c
+++ b/src/gcc/diagnostic.c
@@ -247,7 +247,7 @@
 	real_abort ();
       diagnostic_finish (context);
       fnotice (stderr, "compilation terminated.\n");
-      exit (FATAL_EXIT_CODE);
+      exit (ICE_EXIT_CODE);
 
     default:
       gcc_unreachable ();

Reply to: