X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/8b990b89011d5b954c794e08549776b15e34fff1..13c8f29ce361e3aad71cf2b44e76d5cfdaf7dda3:/src/sysdep.c diff --git a/src/sysdep.c b/src/sysdep.c index cb361ec2dc..460166d119 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1,13 +1,13 @@ /* Interfaces to system-dependent kernel and library entries. - Copyright (C) 1985-1988, 1993-1995, 1999-2015 Free Software + Copyright (C) 1985-1988, 1993-1995, 1999-2016 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -79,9 +79,6 @@ along with GNU Emacs. If not, see . */ #include "msdos.h" #endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif #include #include #include @@ -96,13 +93,21 @@ along with GNU Emacs. If not, see . */ #include "keyboard.h" #include "frame.h" -#include "window.h" #include "termhooks.h" #include "termchar.h" #include "termopts.h" -#include "dispextern.h" #include "process.h" -#include "cm.h" /* for reset_sys_modes */ +#include "cm.h" + +#include "gnutls.h" +/* MS-Windows loads GnuTLS at run time, if available; we don't want to + do that during startup just to call gnutls_rnd. */ +#if 0x020c00 <= GNUTLS_VERSION_NUMBER && !defined WINDOWSNT +# include +#else +# define emacs_gnutls_global_init() Qnil +# define gnutls_rnd(level, data, len) (-1) +#endif #ifdef WINDOWSNT #include @@ -662,14 +667,6 @@ unrequest_sigio (void) interrupts_deferred = 1; #endif } - -void -ignore_sigio (void) -{ -#ifdef USABLE_SIGIO - signal (SIGIO, SIG_IGN); -#endif -} #ifndef MSDOS /* Block SIGCHLD. */ @@ -1623,16 +1620,60 @@ handle_arith_signal (int sig) xsignal0 (Qarith_error); } -#ifdef HAVE_STACK_OVERFLOW_HANDLING - -/* -1 if stack grows down as expected on most OS/ABI variants, 1 otherwise. */ - -static int stack_direction; +#if defined HAVE_STACK_OVERFLOW_HANDLING && !defined WINDOWSNT /* Alternate stack used by SIGSEGV handler below. */ static unsigned char sigsegv_stack[SIGSTKSZ]; + +/* Return true if SIGINFO indicates a stack overflow. */ + +static bool +stack_overflow (siginfo_t *siginfo) +{ + /* In theory, a more-accurate heuristic can be obtained by using + GNU/Linux pthread_getattr_np along with POSIX pthread_attr_getstack + and pthread_attr_getguardsize to find the location and size of the + guard area. In practice, though, these functions are so hard to + use reliably that they're not worth bothering with. E.g., see: + https://sourceware.org/bugzilla/show_bug.cgi?id=16291 + Other operating systems also have problems, e.g., Solaris's + stack_violation function is tailor-made for this problem, but it + doesn't work on Solaris 11.2 x86-64 with a 32-bit executable. + + GNU libsigsegv is overkill for Emacs; otherwise it might be a + candidate here. */ + + if (!siginfo) + return false; + + /* The faulting address. */ + char *addr = siginfo->si_addr; + if (!addr) + return false; + + /* The known top and bottom of the stack. The actual stack may + extend a bit beyond these boundaries. */ + char *bot = stack_bottom; + char *top = near_C_stack_top (); + + /* Log base 2 of the stack heuristic ratio. This ratio is the size + of the known stack divided by the size of the guard area past the + end of the stack top. The heuristic is that a bad address is + considered to be a stack overflow if it occurs within + stacksize>>LG_STACK_HEURISTIC bytes above the top of the known + stack. This heuristic is not exactly correct but it's good + enough in practice. */ + enum { LG_STACK_HEURISTIC = 8 }; + + if (bot < top) + return 0 <= addr - top && addr - top < (top - bot) >> LG_STACK_HEURISTIC; + else + return 0 <= top - addr && top - addr < (bot - top) >> LG_STACK_HEURISTIC; +} + + /* Attempt to recover from SIGSEGV caused by C stack overflow. */ static void @@ -1640,28 +1681,15 @@ handle_sigsegv (int sig, siginfo_t *siginfo, void *arg) { /* Hard GC error may lead to stack overflow caused by too nested calls to mark_object. No way to survive. */ - if (!gc_in_progress) - { - struct rlimit rlim; + bool fatal = gc_in_progress; - if (!getrlimit (RLIMIT_STACK, &rlim)) - { - enum { STACK_DANGER_ZONE = 16 * 1024 }; - char *beg, *end, *addr; - - beg = stack_bottom; - end = stack_bottom + stack_direction * rlim.rlim_cur; - if (beg > end) - addr = beg, beg = end, end = addr; - addr = (char *) siginfo->si_addr; - /* If we're somewhere on stack and too close to - one of its boundaries, most likely this is it. */ - if (beg < addr && addr < end - && (addr - beg < STACK_DANGER_ZONE - || end - addr < STACK_DANGER_ZONE)) - siglongjmp (return_to_command_loop, 1); - } - } +#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD + if (!fatal && !pthread_equal (pthread_self (), main_thread)) + fatal = true; +#endif + + if (!fatal && stack_overflow (siginfo)) + siglongjmp (return_to_command_loop, 1); /* Otherwise we can't do anything with this. */ deliver_fatal_thread_signal (sig); @@ -1676,8 +1704,6 @@ init_sigsegv (void) struct sigaction sa; stack_t ss; - stack_direction = ((char *) &ss < stack_bottom) ? -1 : 1; - ss.ss_sp = sigsegv_stack; ss.ss_size = sizeof (sigsegv_stack); ss.ss_flags = 0; @@ -1690,7 +1716,7 @@ init_sigsegv (void) return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1; } -#else /* not HAVE_STACK_OVERFLOW_HANDLING */ +#else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */ static bool init_sigsegv (void) @@ -1698,7 +1724,7 @@ init_sigsegv (void) return 0; } -#endif /* HAVE_STACK_OVERFLOW_HANDLING */ +#endif /* HAVE_STACK_OVERFLOW_HANDLING && !WINDOWSNT */ static void deliver_arith_signal (int sig) @@ -2052,36 +2078,56 @@ init_signals (bool dumping) # endif /* !HAVE_RANDOM */ #endif /* !RAND_BITS */ +#ifdef HAVE_RANDOM +typedef unsigned int random_seed; +static void set_random_seed (random_seed arg) { srandom (arg); } +#elif defined HAVE_LRAND48 +/* Although srand48 uses a long seed, this is unsigned long to avoid + undefined behavior on signed integer overflow in init_random. */ +typedef unsigned long int random_seed; +static void set_random_seed (random_seed arg) { srand48 (arg); } +#else +typedef unsigned int random_seed; +static void set_random_seed (random_seed arg) { srand (arg); } +#endif + void seed_random (void *seed, ptrdiff_t seed_size) { -#if defined HAVE_RANDOM || ! defined HAVE_LRAND48 - unsigned int arg = 0; -#else - long int arg = 0; -#endif + random_seed arg = 0; unsigned char *argp = (unsigned char *) &arg; unsigned char *seedp = seed; - ptrdiff_t i; - for (i = 0; i < seed_size; i++) + for (ptrdiff_t i = 0; i < seed_size; i++) argp[i % sizeof arg] ^= seedp[i]; -#ifdef HAVE_RANDOM - srandom (arg); -#else -# ifdef HAVE_LRAND48 - srand48 (arg); -# else - srand (arg); -# endif -#endif + set_random_seed (arg); } void init_random (void) { - struct timespec t = current_timespec (); - uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec; - seed_random (&v, sizeof v); + random_seed v; + if (! (EQ (emacs_gnutls_global_init (), Qt) + && gnutls_rnd (GNUTLS_RND_NONCE, &v, sizeof v) == 0)) + { + bool success = false; +#ifndef WINDOWSNT + int fd = emacs_open ("/dev/urandom", O_RDONLY | O_BINARY, 0); + if (0 <= fd) + { + success = emacs_read (fd, &v, sizeof v) == sizeof v; + emacs_close (fd); + } +#else + success = w32_init_random (&v, sizeof v) == 0; +#endif + if (! success) + { + /* Fall back to current time value + PID. */ + struct timespec t = current_timespec (); + v = getpid () ^ t.tv_sec ^ t.tv_nsec; + } + } + set_random_seed (v); } /* @@ -2174,6 +2220,14 @@ emacs_backtrace (int backtrace_limit) else { buffer = main_backtrace_buffer; + + /* Work around 'backtrace' bug; see Bug#19959 and glibc bug#18084. */ + if (bounded_limit < 0) + { + backtrace (buffer, 1); + return; + } + npointers = backtrace (buffer, bounded_limit + 1); } @@ -2693,10 +2747,8 @@ Lisp_Object list_system_processes (void) { Lisp_Object procdir, match, proclist, next; - struct gcpro gcpro1, gcpro2; - register Lisp_Object tail; + Lisp_Object tail; - GCPRO2 (procdir, match); /* For every process on the system, there's a directory in the "/proc" pseudo-directory whose name is the numeric ID of that process. */ @@ -2711,7 +2763,6 @@ list_system_processes (void) next = XCDR (tail); XSETCAR (tail, Fstring_to_number (XCAR (tail), Qnil)); } - UNGCPRO; /* directory_files_internal returns the files in reverse order; undo that. */ @@ -2733,7 +2784,6 @@ list_system_processes (void) struct kinfo_proc *procs; size_t i; - struct gcpro gcpro1; Lisp_Object proclist = Qnil; if (sysctl (mib, 3, NULL, &len, NULL, 0) != 0) @@ -2746,7 +2796,6 @@ list_system_processes (void) return proclist; } - GCPRO1 (proclist); len /= sizeof (struct kinfo_proc); for (i = 0; i < len; i++) { @@ -2756,7 +2805,6 @@ list_system_processes (void) proclist = Fcons (make_fixnum_or_float (procs[i].ki_pid), proclist); #endif } - UNGCPRO; xfree (procs); @@ -2967,7 +3015,6 @@ system_process_attributes (Lisp_Object pid) Lisp_Object attrs = Qnil; Lisp_Object cmd_str, decoded_cmd; ptrdiff_t count; - struct gcpro gcpro1, gcpro2; CHECK_NUMBER_OR_FLOAT (pid); CONS_TO_INTEGER (pid, pid_t, proc_id); @@ -2975,8 +3022,6 @@ system_process_attributes (Lisp_Object pid) if (stat (procfn, &st) < 0) return attrs; - GCPRO2 (attrs, decoded_cmd); - /* euid egid */ uid = st.st_uid; attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs); @@ -3165,7 +3210,6 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); } - UNGCPRO; return attrs; } @@ -3204,7 +3248,6 @@ system_process_attributes (Lisp_Object pid) gid_t gid; Lisp_Object attrs = Qnil; Lisp_Object decoded_cmd; - struct gcpro gcpro1, gcpro2; ptrdiff_t count; CHECK_NUMBER_OR_FLOAT (pid); @@ -3213,8 +3256,6 @@ system_process_attributes (Lisp_Object pid) if (stat (procfn, &st) < 0) return attrs; - GCPRO2 (attrs, decoded_cmd); - /* euid egid */ uid = st.st_uid; attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs); @@ -3307,7 +3348,6 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); } unbind_to (count, Qnil); - UNGCPRO; return attrs; } @@ -3343,7 +3383,6 @@ system_process_attributes (Lisp_Object pid) struct kinfo_proc proc; size_t proclen = sizeof proc; - struct gcpro gcpro1, gcpro2; Lisp_Object attrs = Qnil; Lisp_Object decoded_comm; @@ -3354,8 +3393,6 @@ system_process_attributes (Lisp_Object pid) if (sysctl (mib, 4, &proc, &proclen, NULL, 0) != 0) return attrs; - GCPRO2 (attrs, decoded_comm); - attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (proc.ki_uid)), attrs); block_input (); @@ -3493,7 +3530,6 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qargs, decoded_comm), attrs); } - UNGCPRO; return attrs; }