PR 48931 Use async-signal-safe execve instead of execvp
authorJanne Blomqvist <jb@gcc.gnu.org>
Sun, 29 May 2011 20:13:52 +0000 (23:13 +0300)
committerJanne Blomqvist <jb@gcc.gnu.org>
Sun, 29 May 2011 20:13:52 +0000 (23:13 +0300)
From-SVN: r174415

libgfortran/ChangeLog
libgfortran/libgfortran.h
libgfortran/runtime/backtrace.c
libgfortran/runtime/compile_options.c
libgfortran/runtime/main.c

index f0e3078e8b3623600c405538a89acc0d73c62dad..90929219d8ca1ee8186e44cf1e449880b3260eb1 100644 (file)
@@ -1,3 +1,15 @@
+2011-05-29  Janne Blomqvist  <jb@gcc.gnu.org>
+
+        PR libfortran/48931
+        * libgfortran.h (find_addr2line): New prototype.
+        * runtime/backtrace.c (show_backtrace): Use async-signal-safe
+        execve and stored path of addr2line.
+        * runtime/compile_options.c (maybe_find_addr2line): New function.
+        (set_options): Call maybe_find_addr2line if backtracing is enabled.
+        * runtime/main.c (find_addr2line): New function.
+        (init): Call find_addr2line if backtracing is enabled.
+        (cleanup): Free addr2line_path.
+
 2011-05-29  Janne Blomqvist  <jb@gcc.gnu.org>
 
        PR libfortran/49214
index e77ba10790f77b20088da56b2fc72c5fa5598c5b..b72b250c84a95d6817ff813c20ad7cd9e4b044e3 100644 (file)
@@ -665,6 +665,9 @@ export_proto(store_exe_path);
 extern char * full_exe_path (void);
 internal_proto(full_exe_path);
 
+extern void find_addr2line (void);
+internal_proto(find_addr2line);
+
 /* backtrace.c */
 
 extern void show_backtrace (void);
index 943332ab615b82425945c765101e315158c6c731..7d6479fe9055bf1bd99c8bb12d4bbb034b6f4fd8 100644 (file)
@@ -104,6 +104,9 @@ fd_gets (char *s, int size, int fd)
 }
 
 
+extern char *addr2line_path;
+
+
 /* show_backtrace displays the backtrace, currently obtained by means of
    the glibc backtrace* functions.  */
 
@@ -124,6 +127,9 @@ show_backtrace (void)
 
 #if CAN_PIPE
 
+  if (addr2line_path == NULL)
+    goto fallback_noerr;
+
   /* We attempt to extract file and line information from addr2line.  */
   do
   {
@@ -146,6 +152,7 @@ show_backtrace (void)
        /* Child process.  */
 #define NUM_FIXEDARGS 7
        char *arg[NUM_FIXEDARGS];
+       char *newenv[] = { NULL };
 
        close (f[0]);
 
@@ -160,14 +167,14 @@ show_backtrace (void)
          _exit (1);
        close (f[1]);
 
-       arg[0] = (char *) "addr2line";
+       arg[0] = addr2line_path;
        arg[1] = (char *) "-e";
        arg[2] = full_exe_path ();
        arg[3] = (char *) "-f";
        arg[4] = (char *) "-s";
        arg[5] = (char *) "-C";
        arg[6] = NULL;
-       execvp (arg[0], arg);
+       execve (addr2line_path, arg, newenv);
        _exit (1);
 #undef NUM_FIXEDARGS
       }
@@ -264,6 +271,7 @@ fallback:
 
 #endif /* CAN_PIPE */
 
+fallback_noerr:
   /* Fallback to the glibc backtrace.  */
   estr_write ("\nBacktrace for this error:\n");
   backtrace_symbols_fd (trace, depth, STDERR_FILENO);
index dc0da4bcb90e77f7efba01fab6d7a9e37afc5aad..c3e64de33bad2608c31de1c294ec6dfaab421285 100644 (file)
@@ -58,6 +58,15 @@ backtrace_handler (int signum)
 }
 
 
+/* Helper function for set_options because we need to access the
+   global variable options which is not seen in set_options.  */
+static void
+maybe_find_addr2line (void)
+{
+  if (options.backtrace == -1)
+    find_addr2line ();
+}
+
 /* Set the usual compile-time options.  */
 extern void set_options (int , int []);
 export_proto(set_options);
@@ -131,6 +140,8 @@ set_options (int num, int options[])
 #if defined(SIGXFSZ)
       signal (SIGXFSZ, backtrace_handler);
 #endif
+
+      maybe_find_addr2line ();
     }
 #endif
 
index 54d9e091ce2413d2770e813867c420057204a25a..bc8dab449e8ff247d5be745c7be52d17d353f915 100644 (file)
@@ -139,6 +139,40 @@ full_exe_path (void)
 }
 
 
+char *addr2line_path;
+
+/* Find addr2line and store the path.  */
+
+void
+find_addr2line (void)
+{
+#ifdef HAVE_ACCESS
+#define A2L_LEN 10
+  char *path = getenv ("PATH");
+  size_t n = strlen (path);
+  char ap[n + 1 + A2L_LEN];
+  size_t ai = 0;
+  for (size_t i = 0; i < n; i++)
+    {
+      if (path[i] != ':')
+       ap[ai++] = path[i];
+      else
+       {
+         ap[ai++] = '/';
+         memcpy (ap + ai, "addr2line", A2L_LEN);
+         if (access (ap, R_OK|X_OK) == 0)
+           {
+             addr2line_path = strdup (ap);
+             return;
+           }
+         else
+           ai = 0;
+       }
+    }
+#endif
+}
+
+
 /* Set the saved values of the command line arguments.  */
 
 void
@@ -185,6 +219,9 @@ init (void)
   /* if (argc > 1 && strcmp(argv[1], "--resume") == 0) resume();  */
 #endif
 
+  if (options.backtrace == 1)
+    find_addr2line ();
+
   random_seed_i4 (NULL, NULL, NULL);
 }
 
@@ -198,4 +235,6 @@ cleanup (void)
   
   if (please_free_exe_path_when_done)
     free ((char *) exe_path);
+
+  free (addr2line_path);
 }