PR 67414 Better diagnostics on backtrace failure, gf_strerror bugfix
authorJanne Blomqvist <jb@gcc.gnu.org>
Wed, 2 Sep 2015 14:51:40 +0000 (17:51 +0300)
committerJanne Blomqvist <jb@gcc.gnu.org>
Wed, 2 Sep 2015 14:51:40 +0000 (17:51 +0300)
2015-09-02  Janne Blomqvist  <jb@gcc.gnu.org>

PR libfortran/67414
* io/write.c (gfc_itoa): Move to runtime/string.c.
* libgfortran.h (show_backtrace): Make arg bool.
(gfc_itoa): New prototype.
* runtime/backtrace.c (struct mystate): Change type of try_simple
field, add in_signal_handler field.
(error_callback): Print out error number, or if not in a signal
handler, the error message.
(show_backtrace): Change type of arg, change initialization of
struct mystate.
(backtrace): Call show_backtrace with correct arg type.
* runtime/compile_options.c (backtrace_handler): Call with correct
arg type.
* runtime/error.c (sys_abort): Likewise.
(gf_strerror): Handle newlocale() failure.
* runtime/string.c (gfc_itoa): Function moved here from
io/write.c.

From-SVN: r227404

libgfortran/ChangeLog
libgfortran/io/write.c
libgfortran/libgfortran.h
libgfortran/runtime/backtrace.c
libgfortran/runtime/compile_options.c
libgfortran/runtime/error.c
libgfortran/runtime/string.c

index b3fa76334184bc2d96d10b4391d1b17e34b4f769..0958ca76863b51e047ef8ee11df81076e8240cc4 100644 (file)
@@ -1,3 +1,23 @@
+2015-09-02  Janne Blomqvist  <jb@gcc.gnu.org>
+
+       PR libfortran/67414
+       * io/write.c (gfc_itoa): Move to runtime/string.c.
+       * libgfortran.h (show_backtrace): Make arg bool.
+       (gfc_itoa): New prototype.
+       * runtime/backtrace.c (struct mystate): Change type of try_simple
+       field, add in_signal_handler field.
+       (error_callback): Print out error number, or if not in a signal
+       handler, the error message.
+       (show_backtrace): Change type of arg, change initialization of
+       struct mystate.
+       (backtrace): Call show_backtrace with correct arg type.
+       * runtime/compile_options.c (backtrace_handler): Call with correct
+       arg type.
+       * runtime/error.c (sys_abort): Likewise.
+       (gf_strerror): Handle newlocale() failure.
+       * runtime/string.c (gfc_itoa): Function moved here from
+       io/write.c.
+
 2015-08-31  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
        PR libfortran/47571
index 75996598d0af2fc41d2b01efe86a5e94c2c4a98b..e226236a4b5821f2e72b96f6f41fe5eb082e5516 100644 (file)
@@ -1032,47 +1032,6 @@ ztoa_big (const char *s, char *buffer, int len, GFC_UINTEGER_LARGEST *n)
   return buffer;
 }
 
-/* gfc_itoa()-- Integer to decimal conversion.
-   The itoa function is a widespread non-standard extension to standard
-   C, often declared in <stdlib.h>.  Even though the itoa defined here
-   is a static function we take care not to conflict with any prior
-   non-static declaration.  Hence the 'gfc_' prefix, which is normally
-   reserved for functions with external linkage.  */
-
-static const char *
-gfc_itoa (GFC_INTEGER_LARGEST n, char *buffer, size_t len)
-{
-  int negative;
-  char *p;
-  GFC_UINTEGER_LARGEST t;
-
-  assert (len >= GFC_ITOA_BUF_SIZE);
-
-  if (n == 0)
-    return "0";
-
-  negative = 0;
-  t = n;
-  if (n < 0)
-    {
-      negative = 1;
-      t = -n; /*must use unsigned to protect from overflow*/
-    }
-
-  p = buffer + GFC_ITOA_BUF_SIZE - 1;
-  *p = '\0';
-
-  while (t != 0)
-    {
-      *--p = '0' + (t % 10);
-      t /= 10;
-    }
-
-  if (negative)
-    *--p = '-';
-  return p;
-}
-
 
 void
 write_i (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
index 553cef15b997978d8a0ee63bc854c6b295c0545a..3eb0d85fa245bc676c765c0fac8503fe9f2e9c7d 100644 (file)
@@ -651,7 +651,7 @@ export_proto(store_exe_path);
 
 /* backtrace.c */
 
-extern void show_backtrace (int);
+extern void show_backtrace (bool);
 internal_proto(show_backtrace);
 
 
@@ -838,6 +838,9 @@ internal_proto(fc_strdup);
 extern char *fc_strdup_notrim(const char *, gfc_charlen_type);
 internal_proto(fc_strdup_notrim);
 
+extern const char *gfc_itoa(GFC_INTEGER_LARGEST, char *, size_t);
+internal_proto(gfc_itoa);
+
 /* io/intrinsics.c */
 
 extern void flush_all_units (void);
index 0d7c1fcea22b4e93cdbdc4b906b32f776a1bf350..12ad76aac12b3f448e087244ea362c6dfb1e665d 100644 (file)
@@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -38,8 +39,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 /* Store our own state while backtracing.  */
 struct mystate
 {
-  int try_simple;
   int frame;
+  bool try_simple;
+  bool in_signal_handler;
 };
 
 
@@ -65,15 +67,35 @@ static void
 error_callback (void *data, const char *msg, int errnum)
 {
   struct mystate *state = (struct mystate *) data;
+#define ERRHDR "\nCould not print backtrace: "
+
   if (errnum < 0)
     {
-      state->try_simple = 1;
+      state->try_simple = true;
       return;
     }
-
-  estr_write ("\nSomething went wrong while printing the backtrace: ");
-  estr_write (msg);
-  estr_write ("\n");
+  else if (errnum == 0)
+    {
+      estr_write (ERRHDR);
+      estr_write (msg);
+      estr_write ("\n");
+    }
+  else
+    {
+      char errbuf[256];
+      if (state->in_signal_handler)
+       {
+         estr_write (ERRHDR);
+         estr_write (msg);
+         estr_write (", errno: ");
+         const char *p = gfc_itoa (errnum, errbuf, sizeof (errbuf));
+         estr_write (p);
+         estr_write ("\n");
+       }
+      else
+       st_printf (ERRHDR "%s: %s\n", msg,
+                 gf_strerror (errnum, errbuf, sizeof (errbuf)));
+    }
 }
 
 static int
@@ -110,10 +132,10 @@ full_callback (void *data, uintptr_t pc, const char *filename,
 /* Display the backtrace.  */
 
 void
-show_backtrace (int in_signal_handler)
+show_backtrace (bool in_signal_handler)
 {
   struct backtrace_state *lbstate;
-  struct mystate state = { 0, 0 };
+  struct mystate state = { 0, false, in_signal_handler };
  
   lbstate = backtrace_create_state (NULL, 1, error_callback, NULL);
 
@@ -147,6 +169,6 @@ export_proto (backtrace);
 void
 backtrace (void)
 {
-  show_backtrace (0);
+  show_backtrace (false);
 }
 
index f44256b43b425e899b4f7cbc18e2cf754921d7ec..087c070d3de216c98468d4db7e51256546c7a54c 100644 (file)
@@ -126,7 +126,7 @@ backtrace_handler (int signum)
 
   show_signal (signum);
   estr_write ("\nBacktrace for this error:\n");
-  show_backtrace (1);
+  show_backtrace (true);
 
   /* Now reraise the signal.  We reactivate the signal's
      default handling, which is to terminate the process.
index 9eb07645411ab7f6857bd113b42838b62d013249..4aabe4a4a744d85d4a23d99e8d7393745a02ac3a 100644 (file)
@@ -173,7 +173,7 @@ sys_abort (void)
       || (options.backtrace == -1 && compile_options.backtrace == 1))
     {
       estr_write ("\nProgram aborted. Backtrace:\n");
-      show_backtrace (0);
+      show_backtrace (false);
       signal (SIGABRT, SIG_DFL);
     }
 
@@ -221,8 +221,16 @@ gf_strerror (int errnum,
 #ifdef HAVE_STRERROR_L
   locale_t myloc = newlocale (LC_CTYPE_MASK | LC_MESSAGES_MASK, "",
                              (locale_t) 0);
-  char *p = strerror_l (errnum, myloc);
-  freelocale (myloc);
+  char *p;
+  if (myloc)
+    {
+      p = strerror_l (errnum, myloc);
+      freelocale (myloc);
+    }
+  else
+    /* newlocale might fail e.g. due to running out of memory, fall
+       back to the simpler strerror.  */
+    p = strerror (errnum);
   return p;
 #elif defined(HAVE_STRERROR_R)
 #ifdef HAVE_USELOCALE
index 3c339da22a488a3b4d356aab82ee3decb6e9b684..5bd0f61928e09869b2c1a538bc4abfd2be2e8f87 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C) 2002-2015 Free Software Foundation, Inc.
    Contributed by Paul Brook
 
-This file is part of the GNU Fortran 95 runtime library (libgfortran).
+This file is part of the GNU Fortran runtime library (libgfortran).
 
 Libgfortran is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -167,3 +167,48 @@ find_option (st_parameter_common *cmp, const char *s1, gfc_charlen_type s1_len,
 
   return -1;
 }
+
+
+/* gfc_itoa()-- Integer to decimal conversion.
+   The itoa function is a widespread non-standard extension to
+   standard C, often declared in <stdlib.h>.  Even though the itoa
+   defined here is a static function we take care not to conflict with
+   any prior non-static declaration.  Hence the 'gfc_' prefix, which
+   is normally reserved for functions with external linkage.  Notably,
+   in contrast to the *printf() family of functions, this ought to be
+   async-signal-safe.  */
+
+const char *
+gfc_itoa (GFC_INTEGER_LARGEST n, char *buffer, size_t len)
+{
+  int negative;
+  char *p;
+  GFC_UINTEGER_LARGEST t;
+
+  if (len < GFC_ITOA_BUF_SIZE)
+    sys_abort ();
+
+  if (n == 0)
+    return "0";
+
+  negative = 0;
+  t = n;
+  if (n < 0)
+    {
+      negative = 1;
+      t = -n; /*must use unsigned to protect from overflow*/
+    }
+
+  p = buffer + GFC_ITOA_BUF_SIZE - 1;
+  *p = '\0';
+
+  while (t != 0)
+    {
+      *--p = '0' + (t % 10);
+      t /= 10;
+    }
+
+  if (negative)
+    *--p = '-';
+  return p;
+}