aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2012-10-01 15:12:44 -0700
committerPaul Eggert2012-10-01 15:12:44 -0700
commitaa1ba90e4a95542c83cf636de3bc67e8fb23bad3 (patch)
tree1407a999bbc11bf54aaeba40764d6a75565db182 /src
parentace917bddb2ed2448a97ddf279445bb581c5cd32 (diff)
downloademacs-aa1ba90e4a95542c83cf636de3bc67e8fb23bad3.tar.gz
emacs-aa1ba90e4a95542c83cf636de3bc67e8fb23bad3.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog19
-rw-r--r--src/emacs.c2
-rw-r--r--src/process.c2
-rw-r--r--src/sysdep.c29
-rw-r--r--src/syssignal.h4
5 files changed, 36 insertions, 20 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 7061038fdec..3a94af80c30 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,22 @@
12012-10-01 Paul Eggert <eggert@cs.ucla.edu>
2
3 Fix a malloc race condition involving strsignal.
4 A signal can arrive in the middle of a malloc, and Emacs's signal
5 handler can invoke strsignal, which can invoke malloc, which is
6 not portable. This race condition bug makes Emacs hang on GNU/Linux.
7 Fix it by altering the signal handler so that it does not invoke
8 strsignal.
9 * emacs.c (shut_down_emacs): Use safe_strsignal, not strsignal.
10 * process.c (status_message): Use const pointer, in case strsignal
11 is #defined to safe_strsignal.
12 * sysdep.c (sys_siglist, init_signals): Always define and
13 initialize a substitute sys_siglist if the system does not define
14 one, even if HAVE_STRSIGNAL.
15 (safe_strsignal): Rename from strsignal. Always define,
16 using sys_siglist. Return a const pointer.
17 * syssignal.h (safe_strsignal): New decl.
18 (strsignal) [!HAVE_STRSIGNAL]: Define in terms of safe_strsignal.
19
12012-10-01 Eli Zaretskii <eliz@gnu.org> 202012-10-01 Eli Zaretskii <eliz@gnu.org>
2 21
3 * w32proc.c (timer_loop): Fix code that waits for timer 22 * w32proc.c (timer_loop): Fix code that waits for timer
diff --git a/src/emacs.c b/src/emacs.c
index a603a56b792..bc54f56b98a 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1886,7 +1886,7 @@ shut_down_emacs (int sig, Lisp_Object stuff)
1886 static char const format[] = "Fatal error %d: "; 1886 static char const format[] = "Fatal error %d: ";
1887 char buf[sizeof format - 2 + INT_STRLEN_BOUND (int)]; 1887 char buf[sizeof format - 2 + INT_STRLEN_BOUND (int)];
1888 int buflen = sprintf (buf, format, sig); 1888 int buflen = sprintf (buf, format, sig);
1889 char const *sig_desc = strsignal (sig); 1889 char const *sig_desc = safe_strsignal (sig);
1890 ignore_value (write (STDERR_FILENO, buf, buflen)); 1890 ignore_value (write (STDERR_FILENO, buf, buflen));
1891 ignore_value (write (STDERR_FILENO, sig_desc, strlen (sig_desc))); 1891 ignore_value (write (STDERR_FILENO, sig_desc, strlen (sig_desc)));
1892 } 1892 }
diff --git a/src/process.c b/src/process.c
index dfc89809fa5..92bea0d3a27 100644
--- a/src/process.c
+++ b/src/process.c
@@ -570,7 +570,7 @@ status_message (struct Lisp_Process *p)
570 570
571 if (EQ (symbol, Qsignal) || EQ (symbol, Qstop)) 571 if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
572 { 572 {
573 char *signame; 573 char const *signame;
574 synchronize_system_messages_locale (); 574 synchronize_system_messages_locale ();
575 signame = strsignal (code); 575 signame = strsignal (code);
576 if (signame == 0) 576 if (signame == 0)
diff --git a/src/sysdep.c b/src/sysdep.c
index a825145c6dd..74617fcaf0f 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -1543,12 +1543,10 @@ deliver_thread_signal (int sig, signal_handler_t handler)
1543 errno = old_errno; 1543 errno = old_errno;
1544} 1544}
1545 1545
1546#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST 1546#if !HAVE_DECL_SYS_SIGLIST
1547static char *my_sys_siglist[NSIG]; 1547# undef sys_siglist
1548# ifdef sys_siglist
1549# undef sys_siglist
1550# endif
1551# define sys_siglist my_sys_siglist 1548# define sys_siglist my_sys_siglist
1549static char const *sys_siglist[NSIG];
1552#endif 1550#endif
1553 1551
1554/* Handle bus errors, invalid instruction, etc. */ 1552/* Handle bus errors, invalid instruction, etc. */
@@ -1611,7 +1609,7 @@ init_signals (bool dumping)
1611 main_thread = pthread_self (); 1609 main_thread = pthread_self ();
1612#endif 1610#endif
1613 1611
1614#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST 1612#if !HAVE_DECL_SYS_SIGLIST
1615 if (! initialized) 1613 if (! initialized)
1616 { 1614 {
1617 sys_siglist[SIGABRT] = "Aborted"; 1615 sys_siglist[SIGABRT] = "Aborted";
@@ -1759,7 +1757,7 @@ init_signals (bool dumping)
1759 sys_siglist[SIGXFSZ] = "File size limit exceeded"; 1757 sys_siglist[SIGXFSZ] = "File size limit exceeded";
1760# endif 1758# endif
1761 } 1759 }
1762#endif /* !defined HAVE_STRSIGNAL && !defined HAVE_DECL_SYS_SIGLIST */ 1760#endif /* !HAVE_DECL_SYS_SIGLIST */
1763 1761
1764 /* Don't alter signal handlers if dumping. On some machines, 1762 /* Don't alter signal handlers if dumping. On some machines,
1765 changing signal handlers sets static data that would make signals 1763 changing signal handlers sets static data that would make signals
@@ -2280,21 +2278,20 @@ set_file_times (int fd, const char *filename,
2280 return fdutimens (fd, filename, timespec); 2278 return fdutimens (fd, filename, timespec);
2281} 2279}
2282 2280
2283#ifndef HAVE_STRSIGNAL 2281/* Like strsignal, except async-signal-safe, and this function typically
2284char * 2282 returns a string in the C locale rather than the current locale. */
2285strsignal (int code) 2283char const *
2284safe_strsignal (int code)
2286{ 2285{
2287 char *signame = 0; 2286 char const *signame = 0;
2288 2287
2289 if (0 <= code && code < NSIG) 2288 if (0 <= code && code < NSIG)
2290 { 2289 signame = sys_siglist[code];
2291 /* Cast to suppress warning if the table has const char *. */ 2290 if (! signame)
2292 signame = (char *) sys_siglist[code]; 2291 signame = "Unknown signal";
2293 }
2294 2292
2295 return signame; 2293 return signame;
2296} 2294}
2297#endif /* HAVE_STRSIGNAL */
2298 2295
2299#ifndef DOS_NT 2296#ifndef DOS_NT
2300/* For make-serial-process */ 2297/* For make-serial-process */
diff --git a/src/syssignal.h b/src/syssignal.h
index ece2515dec9..66538aad100 100644
--- a/src/syssignal.h
+++ b/src/syssignal.h
@@ -39,6 +39,7 @@ extern sigset_t empty_mask;
39typedef void (*signal_handler_t) (int); 39typedef void (*signal_handler_t) (int);
40 40
41extern void emacs_sigaction_init (struct sigaction *, signal_handler_t); 41extern void emacs_sigaction_init (struct sigaction *, signal_handler_t);
42char const *safe_strsignal (int);
42 43
43#if NSIG < NSIG_MINIMUM 44#if NSIG < NSIG_MINIMUM
44# undef NSIG 45# undef NSIG
@@ -70,8 +71,7 @@ extern void emacs_sigaction_init (struct sigaction *, signal_handler_t);
70#endif /* ! defined (SIGCLD) */ 71#endif /* ! defined (SIGCLD) */
71 72
72#ifndef HAVE_STRSIGNAL 73#ifndef HAVE_STRSIGNAL
73/* strsignal is in sysdep.c */ 74# define strsignal(sig) safe_strsignal (sig)
74char *strsignal (int);
75#endif 75#endif
76 76
77void deliver_process_signal (int, signal_handler_t); 77void deliver_process_signal (int, signal_handler_t);