]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix a malloc race condition involving strsignal.
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 1 Oct 2012 22:12:44 +0000 (15:12 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 1 Oct 2012 22:12:44 +0000 (15:12 -0700)
A signal can arrive in the middle of a malloc, and Emacs's signal
handler can invoke strsignal, which can invoke malloc, which is
not portable.  This race condition bug makes Emacs hang on GNU/Linux.
Fix it by altering the signal handler so that it does not invoke
strsignal.
* emacs.c (shut_down_emacs): Use safe_strsignal, not strsignal.
* process.c (status_message): Use const pointer, in case strsignal
is #defined to safe_strsignal.
* sysdep.c (sys_siglist, init_signals): Always define and
initialize a substitute sys_siglist if the system does not define
one, even if HAVE_STRSIGNAL.
(safe_strsignal): Rename from strsignal.  Always define,
using sys_siglist.  Return a const pointer.
* syssignal.h (safe_strsignal): New decl.
(strsignal) [!HAVE_STRSIGNAL]: Define in terms of safe_strsignal.

src/ChangeLog
src/emacs.c
src/process.c
src/sysdep.c
src/syssignal.h

index 7061038fdec1ffa25a68b7b6cf82b6f5f435337a..3a94af80c306435aa41bc5de05941ee5a7ed03f0 100644 (file)
@@ -1,3 +1,22 @@
+2012-10-01  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Fix a malloc race condition involving strsignal.
+       A signal can arrive in the middle of a malloc, and Emacs's signal
+       handler can invoke strsignal, which can invoke malloc, which is
+       not portable.  This race condition bug makes Emacs hang on GNU/Linux.
+       Fix it by altering the signal handler so that it does not invoke
+       strsignal.
+       * emacs.c (shut_down_emacs): Use safe_strsignal, not strsignal.
+       * process.c (status_message): Use const pointer, in case strsignal
+       is #defined to safe_strsignal.
+       * sysdep.c (sys_siglist, init_signals): Always define and
+       initialize a substitute sys_siglist if the system does not define
+       one, even if HAVE_STRSIGNAL.
+       (safe_strsignal): Rename from strsignal.  Always define,
+       using sys_siglist.  Return a const pointer.
+       * syssignal.h (safe_strsignal): New decl.
+       (strsignal) [!HAVE_STRSIGNAL]: Define in terms of safe_strsignal.
+
 2012-10-01  Eli Zaretskii  <eliz@gnu.org>
 
        * w32proc.c (timer_loop): Fix code that waits for timer
index a603a56b792f40502e996bd196e0fcc45974bfcd..bc54f56b98a2501c77a3859f5850d90488e6ca52 100644 (file)
@@ -1886,7 +1886,7 @@ shut_down_emacs (int sig, Lisp_Object stuff)
            static char const format[] = "Fatal error %d: ";
            char buf[sizeof format - 2 + INT_STRLEN_BOUND (int)];
            int buflen = sprintf (buf, format, sig);
-           char const *sig_desc = strsignal (sig);
+           char const *sig_desc = safe_strsignal (sig);
            ignore_value (write (STDERR_FILENO, buf, buflen));
            ignore_value (write (STDERR_FILENO, sig_desc, strlen (sig_desc)));
          }
index dfc89809fa5ff58999dfeb4013c7ab153c3ff73f..92bea0d3a271d381b2e8504e98670c678efe0b70 100644 (file)
@@ -570,7 +570,7 @@ status_message (struct Lisp_Process *p)
 
   if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
     {
-      char *signame;
+      char const *signame;
       synchronize_system_messages_locale ();
       signame = strsignal (code);
       if (signame == 0)
index a825145c6ddbc2189687c07cb84dc974288013a3..74617fcaf0f14715baf257fce37765624df43ae6 100644 (file)
@@ -1543,12 +1543,10 @@ deliver_thread_signal (int sig, signal_handler_t handler)
   errno = old_errno;
 }
 \f
-#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
-static char *my_sys_siglist[NSIG];
-# ifdef sys_siglist
-#  undef sys_siglist
-# endif
+#if !HAVE_DECL_SYS_SIGLIST
+# undef sys_siglist
 # define sys_siglist my_sys_siglist
+static char const *sys_siglist[NSIG];
 #endif
 
 /* Handle bus errors, invalid instruction, etc.  */
@@ -1611,7 +1609,7 @@ init_signals (bool dumping)
   main_thread = pthread_self ();
 #endif
 
-#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
+#if !HAVE_DECL_SYS_SIGLIST
   if (! initialized)
     {
       sys_siglist[SIGABRT] = "Aborted";
@@ -1759,7 +1757,7 @@ init_signals (bool dumping)
       sys_siglist[SIGXFSZ] = "File size limit exceeded";
 # endif
     }
-#endif /* !defined HAVE_STRSIGNAL && !defined HAVE_DECL_SYS_SIGLIST */
+#endif /* !HAVE_DECL_SYS_SIGLIST */
 
   /* Don't alter signal handlers if dumping.  On some machines,
      changing signal handlers sets static data that would make signals
@@ -2280,21 +2278,20 @@ set_file_times (int fd, const char *filename,
   return fdutimens (fd, filename, timespec);
 }
 \f
-#ifndef HAVE_STRSIGNAL
-char *
-strsignal (int code)
+/* Like strsignal, except async-signal-safe, and this function typically
+   returns a string in the C locale rather than the current locale.  */
+char const *
+safe_strsignal (int code)
 {
-  char *signame = 0;
+  char const *signame = 0;
 
   if (0 <= code && code < NSIG)
-    {
-      /* Cast to suppress warning if the table has const char *.  */
-      signame = (char *) sys_siglist[code];
-    }
+    signame = sys_siglist[code];
+  if (! signame)
+    signame = "Unknown signal";
 
   return signame;
 }
-#endif /* HAVE_STRSIGNAL */
 \f
 #ifndef DOS_NT
 /* For make-serial-process  */
index ece2515dec9e573d4677e6340e95a7568756e8f4..66538aad100ce7550a2b3616d2bd61ad556c7712 100644 (file)
@@ -39,6 +39,7 @@ extern sigset_t empty_mask;
 typedef void (*signal_handler_t) (int);
 
 extern void emacs_sigaction_init (struct sigaction *, signal_handler_t);
+char const *safe_strsignal (int);
 
 #if NSIG < NSIG_MINIMUM
 # undef NSIG
@@ -70,8 +71,7 @@ extern void emacs_sigaction_init (struct sigaction *, signal_handler_t);
 #endif /* ! defined (SIGCLD) */
 
 #ifndef HAVE_STRSIGNAL
-/* strsignal is in sysdep.c */
-char *strsignal (int);
+# define strsignal(sig) safe_strsignal (sig)
 #endif
 
 void deliver_process_signal (int, signal_handler_t);