Commit aa1ba90e authored by Paul Eggert's avatar Paul Eggert
Browse files

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.
parent ace917bd
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> 2012-10-01 Eli Zaretskii <eliz@gnu.org>
   
* w32proc.c (timer_loop): Fix code that waits for timer * w32proc.c (timer_loop): Fix code that waits for timer
......
...@@ -1886,7 +1886,7 @@ shut_down_emacs (int sig, Lisp_Object stuff) ...@@ -1886,7 +1886,7 @@ shut_down_emacs (int sig, Lisp_Object stuff)
static char const format[] = "Fatal error %d: "; static char const format[] = "Fatal error %d: ";
char buf[sizeof format - 2 + INT_STRLEN_BOUND (int)]; char buf[sizeof format - 2 + INT_STRLEN_BOUND (int)];
int buflen = sprintf (buf, format, sig); 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, buf, buflen));
ignore_value (write (STDERR_FILENO, sig_desc, strlen (sig_desc))); ignore_value (write (STDERR_FILENO, sig_desc, strlen (sig_desc)));
} }
......
...@@ -570,7 +570,7 @@ status_message (struct Lisp_Process *p) ...@@ -570,7 +570,7 @@ status_message (struct Lisp_Process *p)
if (EQ (symbol, Qsignal) || EQ (symbol, Qstop)) if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
{ {
char *signame; char const *signame;
synchronize_system_messages_locale (); synchronize_system_messages_locale ();
signame = strsignal (code); signame = strsignal (code);
if (signame == 0) if (signame == 0)
......
...@@ -1543,12 +1543,10 @@ deliver_thread_signal (int sig, signal_handler_t handler) ...@@ -1543,12 +1543,10 @@ deliver_thread_signal (int sig, signal_handler_t handler)
errno = old_errno; errno = old_errno;
} }
#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST #if !HAVE_DECL_SYS_SIGLIST
static char *my_sys_siglist[NSIG]; # undef sys_siglist
# ifdef sys_siglist
# undef sys_siglist
# endif
# define sys_siglist my_sys_siglist # define sys_siglist my_sys_siglist
static char const *sys_siglist[NSIG];
#endif #endif
/* Handle bus errors, invalid instruction, etc. */ /* Handle bus errors, invalid instruction, etc. */
...@@ -1611,7 +1609,7 @@ init_signals (bool dumping) ...@@ -1611,7 +1609,7 @@ init_signals (bool dumping)
main_thread = pthread_self (); main_thread = pthread_self ();
#endif #endif
#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST #if !HAVE_DECL_SYS_SIGLIST
if (! initialized) if (! initialized)
{ {
sys_siglist[SIGABRT] = "Aborted"; sys_siglist[SIGABRT] = "Aborted";
...@@ -1759,7 +1757,7 @@ init_signals (bool dumping) ...@@ -1759,7 +1757,7 @@ init_signals (bool dumping)
sys_siglist[SIGXFSZ] = "File size limit exceeded"; sys_siglist[SIGXFSZ] = "File size limit exceeded";
# endif # 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, /* Don't alter signal handlers if dumping. On some machines,
changing signal handlers sets static data that would make signals changing signal handlers sets static data that would make signals
...@@ -2280,21 +2278,20 @@ set_file_times (int fd, const char *filename, ...@@ -2280,21 +2278,20 @@ set_file_times (int fd, const char *filename,
return fdutimens (fd, filename, timespec); return fdutimens (fd, filename, timespec);
} }
#ifndef HAVE_STRSIGNAL /* Like strsignal, except async-signal-safe, and this function typically
char * returns a string in the C locale rather than the current locale. */
strsignal (int code) char const *
safe_strsignal (int code)
{ {
char *signame = 0; char const *signame = 0;
if (0 <= code && code < NSIG) if (0 <= code && code < NSIG)
{ signame = sys_siglist[code];
/* Cast to suppress warning if the table has const char *. */ if (! signame)
signame = (char *) sys_siglist[code]; signame = "Unknown signal";
}
return signame; return signame;
} }
#endif /* HAVE_STRSIGNAL */
#ifndef DOS_NT #ifndef DOS_NT
/* For make-serial-process */ /* For make-serial-process */
......
...@@ -39,6 +39,7 @@ extern sigset_t empty_mask; ...@@ -39,6 +39,7 @@ extern sigset_t empty_mask;
typedef void (*signal_handler_t) (int); typedef void (*signal_handler_t) (int);
extern void emacs_sigaction_init (struct sigaction *, signal_handler_t); extern void emacs_sigaction_init (struct sigaction *, signal_handler_t);
char const *safe_strsignal (int);
#if NSIG < NSIG_MINIMUM #if NSIG < NSIG_MINIMUM
# undef NSIG # undef NSIG
...@@ -70,8 +71,7 @@ extern void emacs_sigaction_init (struct sigaction *, signal_handler_t); ...@@ -70,8 +71,7 @@ extern void emacs_sigaction_init (struct sigaction *, signal_handler_t);
#endif /* ! defined (SIGCLD) */ #endif /* ! defined (SIGCLD) */
#ifndef HAVE_STRSIGNAL #ifndef HAVE_STRSIGNAL
/* strsignal is in sysdep.c */ # define strsignal(sig) safe_strsignal (sig)
char *strsignal (int);
#endif #endif
void deliver_process_signal (int, signal_handler_t); void deliver_process_signal (int, signal_handler_t);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment