unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv
@ 2015-07-07 20:11 Ken Brown
  2015-07-08 13:33 ` Wolfgang Jenkner
  2015-07-16  7:58 ` Paul Eggert
  0 siblings, 2 replies; 7+ messages in thread
From: Ken Brown @ 2015-07-07 20:11 UTC (permalink / raw)
  To: 21004

There is a call to setrlimit in main() that tries to increase the stack
size.  As a result of this, the value of rlim.rlim_cur in
handle_sigsegv() might exceed the actual stack size.  See Corinna
Vinschen's message at

   https://www.cygwin.com/ml/cygwin/2015-07/msg00092.html

for a more detailed explanation.

Corinna suggests using pthread_getattr_np instead of getrlimit to avoid
this problem, as in the following patch:

diff --git a/src/sysdep.c b/src/sysdep.c
index 91036f0..c49e333 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -1625,6 +1625,8 @@ handle_arith_signal (int sig)

#ifdef HAVE_STACK_OVERFLOW_HANDLING

+#include <pthread.h>
+
/* -1 if stack grows down as expected on most OS/ABI variants, 1 
otherwise.  */

static int stack_direction;
@@ -1642,9 +1644,11 @@ handle_sigsegv (int sig, siginfo_t *siginfo, void 
*arg)
too nested calls to mark_object.  No way to survive.  */
if (!gc_in_progress)
{
-      struct rlimit rlim;
+      pthread_attr_t attr;
+      size_t stacksize;

-      if (!getrlimit (RLIMIT_STACK, &rlim))
+      if (!pthread_getattr_np (pthread_self (), &attr)
+         && !pthread_attr_getstacksize (&attr, &stacksize))
{
/* STACK_DANGER_ZONE has to be bigger than 16K on Cygwin, for
reasons explained in
@@ -1657,7 +1661,7 @@ handle_sigsegv (int sig, siginfo_t *siginfo, void 
*arg)
char *beg, *end, *addr;

beg = stack_bottom;
-         end = stack_bottom + stack_direction * rlim.rlim_cur;
+         end = stack_bottom + stack_direction * stacksize;
if (beg > end)
addr = beg, beg = end, end = addr;
addr = (char *) siginfo->si_addr;

Of course, the definition of HAVE_STACK_OVERFLOW_HANDLING would have to
be changed to ensure that pthread_getattr_np exists.

In GNU Emacs 25.0.50.17 (x86_64-unknown-cygwin, GTK+ Version 3.14.13)
  of 2015-07-07 on moufang
Repository revision: 0bfc94047da4960af55196242728a7a55120867f
Windowing system distributor `The Cygwin/X Project', version 11.0.11701000
Configured using:
  `configure 'CFLAGS=-g3 -O0''

Configured features:
XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND DBUS GSETTINGS NOTIFY ACL
GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB TOOLKIT_SCROLL_BARS
GTK3 X11

Important settings:
   value of $LANG: en_US.UTF-8
   locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
   tooltip-mode: t
   global-eldoc-mode: t
   electric-indent-mode: t
   mouse-wheel-mode: t
   tool-bar-mode: t
   menu-bar-mode: t
   file-name-shadow-mode: t
   global-font-lock-mode: t
   font-lock-mode: t
   blink-cursor-mode: t
   auto-composition-mode: t
   auto-encryption-mode: t
   auto-compression-mode: t
   line-number-mode: t
   transient-mark-mode: t

Recent messages:
For information about GNU Emacs and the GNU system, type C-h C-a.
Making completion list...

Load-path shadows:
None found.

Features:
(shadow sort gnus-util mail-extr emacsbug message dired format-spec
rfc822 mml mml-sec mm-decode mm-bodies mm-encode mail-parse rfc2231
mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045 ietf-drums
mm-util help-fns help-mode easymenu cl-loaddefs pcase cl-lib mail-prsvr
mail-utils time-date mule-util tooltip eldoc electric uniquify
ediff-hook vc-hooks lisp-float-type mwheel x-win term/common-win x-dnd
tool-bar dnd fontset image regexp-opt fringe tabulated-list newcomment
elisp-mode lisp-mode prog-mode register page menu-bar rfn-eshadow timer
select scroll-bar mouse jit-lock font-lock syntax facemenu font-core
frame cl-generic cham georgian utf-8-lang misc-lang vietnamese tibetan
thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian
slovak czech european ethiopic indian cyrillic chinese charscript
case-table epa-hook jka-cmpr-hook help simple abbrev minibuffer
cl-preloaded nadvice loaddefs button faces cus-face macroexp files
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget hashtable-print-readable backquote dbusbind gfilenotify
dynamic-setting system-font-setting font-render-setting move-toolbar gtk
x-toolkit x multi-tty make-network-process emacs)





^ permalink raw reply related	[flat|nested] 7+ messages in thread

* bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv
  2015-07-07 20:11 bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv Ken Brown
@ 2015-07-08 13:33 ` Wolfgang Jenkner
  2015-07-08 14:20   ` Ken Brown
  2015-07-16  7:58 ` Paul Eggert
  1 sibling, 1 reply; 7+ messages in thread
From: Wolfgang Jenkner @ 2015-07-08 13:33 UTC (permalink / raw)
  To: Ken Brown; +Cc: 21004

On Tue, Jul 07 2015, Ken Brown wrote:

> Of course, the definition of HAVE_STACK_OVERFLOW_HANDLING would have to
> be changed to ensure that pthread_getattr_np exists.

Other systems may have this under a different name (e.g., FreeBSD has
pthread_attr_get_np and needs to include pthread_np.h).  By the way,
Guile has already some code to deal with this.





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv
  2015-07-08 13:33 ` Wolfgang Jenkner
@ 2015-07-08 14:20   ` Ken Brown
  0 siblings, 0 replies; 7+ messages in thread
From: Ken Brown @ 2015-07-08 14:20 UTC (permalink / raw)
  To: Wolfgang Jenkner; +Cc: Dmitry Antipov, 21004

On 7/8/2015 9:33 AM, Wolfgang Jenkner wrote:
> On Tue, Jul 07 2015, Ken Brown wrote:
>
>> Of course, the definition of HAVE_STACK_OVERFLOW_HANDLING would have to
>> be changed to ensure that pthread_getattr_np exists.
>
> Other systems may have this under a different name (e.g., FreeBSD has
> pthread_attr_get_np and needs to include pthread_np.h).  By the way,
> Guile has already some code to deal with this.

So someone (Dmitry?) would have to do some work to make this more 
portable.  It may or may not be worth the trouble; I'm not even sure yet 
that recovery from stack overflow actually works (see bug#20996).

Ken






^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv
  2015-07-07 20:11 bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv Ken Brown
  2015-07-08 13:33 ` Wolfgang Jenkner
@ 2015-07-16  7:58 ` Paul Eggert
  2015-07-16 12:15   ` Ken Brown
  2015-07-16 14:34   ` Eli Zaretskii
  1 sibling, 2 replies; 7+ messages in thread
From: Paul Eggert @ 2015-07-16  7:58 UTC (permalink / raw)
  To: Ken Brown; +Cc: Wolfgang Jenkner, Corinna Vinschen, Dmitry Antipov, 21004

[-- Attachment #1: Type: text/plain, Size: 300 bytes --]

Ken, thanks for reporting the problem in <http://bugs.gnu.org/21004>.  Please 
try the attached patch.  Although it avoids getrlimit and it works for me on 
both GNU/Linux and Solaris, I can't easily test it on Cygwin.  I'll CC: this to 
Eli as a heads-up, as he's interested in the MS-Windows case.

[-- Attachment #2: 0001-Better-heuristic-for-C-stack-overflow.patch --]
[-- Type: text/x-diff, Size: 6196 bytes --]

From 4cb3a1e2e3563a1dc0969bce3edd84918067d199 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 16 Jul 2015 00:48:40 -0700
Subject: [PATCH] Better heuristic for C stack overflow

Improve the heuristic for distinguishing stack overflows from
other SIGSEGV causes (Bug#21004).  Corinna Vinschen explained that
the getrlimit method wasn't portable to Cygwin; see:
https://www.cygwin.com/ml/cygwin/2015-07/msg00092.html
Corinna suggested pthread_getattr_np but this also has problems.
Instead, replace the low-level system stuff with a simple
heuristic based on known good stack addresses.
* src/eval.c, src/lisp.h (near_C_stack_top): New function.
* src/sysdep.c: Don't include <sys/resource.h>.
(stack_direction): Remove.  All uses removed.
(stack_overflow): New function.
(handle_sigsegv): Use it instead of incorrect getrlimit heuristic.
Make SEGV fatal in non-main threads.
---
 src/eval.c   |  6 ++++
 src/lisp.h   |  1 +
 src/sysdep.c | 93 ++++++++++++++++++++++++++++++++++++------------------------
 3 files changed, 63 insertions(+), 37 deletions(-)

diff --git a/src/eval.c b/src/eval.c
index 4f7f42f..9bdcf4b 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -200,6 +200,12 @@ backtrace_next (union specbinding *pdl)
   return pdl;
 }
 
+/* Return a pointer to somewhere near the top of the C stack.  */
+void *
+near_C_stack_top (void)
+{
+  return backtrace_args (backtrace_top ());
+}
 
 void
 init_eval_once (void)
diff --git a/src/lisp.h b/src/lisp.h
index c3289c9..341603f 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4029,6 +4029,7 @@ extern _Noreturn void verror (const char *, va_list)
   ATTRIBUTE_FORMAT_PRINTF (1, 0);
 extern void un_autoload (Lisp_Object);
 extern Lisp_Object call_debugger (Lisp_Object arg);
+extern void *near_C_stack_top (void);
 extern void init_eval_once (void);
 extern Lisp_Object safe_call (ptrdiff_t, Lisp_Object, ...);
 extern Lisp_Object safe_call1 (Lisp_Object, Lisp_Object);
diff --git a/src/sysdep.c b/src/sysdep.c
index 91036f0..30a55f1 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -79,9 +79,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "msdos.h"
 #endif
 
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
 #include <sys/param.h>
 #include <sys/file.h>
 #include <fcntl.h>
@@ -1625,14 +1622,58 @@ handle_arith_signal (int sig)
 
 #ifdef HAVE_STACK_OVERFLOW_HANDLING
 
-/* -1 if stack grows down as expected on most OS/ABI variants, 1 otherwise.  */
-
-static int stack_direction;
-
 /* 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,35 +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))
-	{
-	  /* STACK_DANGER_ZONE has to be bigger than 16K on Cygwin, for
-	     reasons explained in
-	     https://www.cygwin.com/ml/cygwin/2015-06/msg00381.html.  */
-#ifdef CYGWIN
-	  enum { STACK_DANGER_ZONE = 32 * 1024 };
-#else
-	  enum { STACK_DANGER_ZONE = 16 * 1024 };
-#endif
-	  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);
@@ -1683,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;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv
  2015-07-16  7:58 ` Paul Eggert
@ 2015-07-16 12:15   ` Ken Brown
  2015-07-16 14:34   ` Eli Zaretskii
  1 sibling, 0 replies; 7+ messages in thread
From: Ken Brown @ 2015-07-16 12:15 UTC (permalink / raw)
  To: Paul Eggert; +Cc: Wolfgang Jenkner, Corinna Vinschen, Dmitry Antipov, 21004

On 7/16/2015 3:58 AM, Paul Eggert wrote:
> Ken, thanks for reporting the problem in <http://bugs.gnu.org/21004>.  Please
> try the attached patch.  Although it avoids getrlimit and it works for me on
> both GNU/Linux and Solaris, I can't easily test it on Cygwin.  I'll CC: this to
> Eli as a heads-up, as he's interested in the MS-Windows case.

It works on Cygwin.  Thanks.

Ken





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv
  2015-07-16  7:58 ` Paul Eggert
  2015-07-16 12:15   ` Ken Brown
@ 2015-07-16 14:34   ` Eli Zaretskii
  2015-07-16 14:38     ` Paul Eggert
  1 sibling, 1 reply; 7+ messages in thread
From: Eli Zaretskii @ 2015-07-16 14:34 UTC (permalink / raw)
  To: Paul Eggert; +Cc: wjenkner, corinna-cygwin, dmantipov, 21004

> Date: Thu, 16 Jul 2015 00:58:10 -0700
> From: Paul Eggert <eggert@cs.ucla.edu>
> CC: 21004@debbugs.gnu.org, Eli Zaretskii <eliz@gnu.org>, 
>  Wolfgang Jenkner <wjenkner@inode.at>,
>  Dmitry Antipov <dmantipov@yandex.ru>, 
>  Corinna Vinschen <corinna-cygwin@cygwin.com>
> 
> Ken, thanks for reporting the problem in <http://bugs.gnu.org/21004>.  Please 
> try the attached patch.  Although it avoids getrlimit and it works for me on 
> both GNU/Linux and Solaris, I can't easily test it on Cygwin.  I'll CC: this to 
> Eli as a heads-up, as he's interested in the MS-Windows case.

Thanks.  The native MS-Windows build doesn't (yet) support
stack-overflow recovery, so the affected code is not compiled into
that build.





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv
  2015-07-16 14:34   ` Eli Zaretskii
@ 2015-07-16 14:38     ` Paul Eggert
  0 siblings, 0 replies; 7+ messages in thread
From: Paul Eggert @ 2015-07-16 14:38 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: wjenkner, dmantipov, 21004-done

Thanks, Ken and Eli, for the quick responses.  I've installed the patch as 
master commit a5522abbca2235771384949dfa87c8efc68831b2 and am closing the bug.





^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-07-16 14:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-07 20:11 bug#21004: 25.0.50; Questionable call to getrlimit in handle_sigsegv Ken Brown
2015-07-08 13:33 ` Wolfgang Jenkner
2015-07-08 14:20   ` Ken Brown
2015-07-16  7:58 ` Paul Eggert
2015-07-16 12:15   ` Ken Brown
2015-07-16 14:34   ` Eli Zaretskii
2015-07-16 14:38     ` Paul Eggert

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).