| 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. |
| |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| + reproducible 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,224 @@ 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 + 3) * sizeof (const char *)); |
| + 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-"; |
| + |
| + 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 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, (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 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) |
| + { |
| + 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. */ |
| |
| |
| @@ -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 |