[PATCH] Improve stackdumps on x86_64

Jon TURNEY jon.turney@dronecode.org.uk
Thu Mar 12 14:05:00 GMT 2015


I was looking at the crash reported at [1]. Processing the stackdump gives:

> 0x000000018006ff23    signal_exit                                exceptions.cc:1234
> 0x00000001800713ea    _cygtls::call_signal_handler()             exceptions.cc:1490
> 0x0000000180121d04    sig_send(_pinfo*, siginfo_t&, _cygtls*)    sigproc.cc:714
> 0x000000018011ee5e    _pinfo::kill(siginfo_t&)                   signal.cc:252
> 0x000000018011f32b    kill0                                      signal.cc:303
> 0x000000018011f4fc    raise                                      signal.cc:289
> 0x000000018011f7bf    abort                                      signal.cc:376
> 0x00000001801528c5    dlfree                                     malloc.cc:4762
> 0x00000001800c52b3    free                                       sync.h:36
> 0x000000018011ae5b    ??                                         sigfe.s:43

Which is not entirely helpful.

We can see that an abort signal is being raised inside free, but the 
stacktrace stops at _sigbe, because unwinding that frame requires 
special measures.

Presumably run has some invalid heap use going on, but annoyingly the 
stackdump stops short of identifying the problem line.

Attached is a patch which teaches stack_info::walk() how to unwind these 
frames on x86_64.

Also attached is a small testcase, which currently produces a similar 
stackdump truncated at _sigbe, or with my patch applied:

> 0x0000000180070238    signal_exit                                exceptions.cc:1321
> 0x000000018007172a    _cygtls::call_signal_handler()             exceptions.cc:1578
> 0x0000000180127e2f    sig_send(_pinfo*, siginfo_t&, _cygtls*)    sigproc.cc:714
> 0x0000000180124fb0    _pinfo::kill(siginfo_t&)                   signal.cc:252
> 0x0000000180125479    kill0                                      signal.cc:303
> 0x000000018012564c    raise                                      signal.cc:289
> 0x000000018012590f    abort                                      signal.cc:376
> 0x000000018015969a    dlfree                                     malloc.cc:4717
> 0x00000001800ca103    free                                       sync.h:36
> 0x0000000180120f5b    ?? (_sigbe)                                sigfe.s:54
> 0x0000000100401119    foo                                        malloc-corruption-abort.c:11
> 0x000000010040113b    sighandler                                 malloc-corruption-abort.c:17
> 0x000000018007172a    _cygtls::call_signal_handler()             exceptions.cc:1578
> 0x0000000180121078    ?? (sigdelayed)                            sigfe.s:144
> 0x0000000100401174    main                                       malloc-corruption-abort.c:32

The x86 unwinder could probably benefit from something similar, but it 
seems to be able to do a slightly better job of escaping from _sigbe, I 
guess due to the frame pointer.

[1] https://cygwin.com/ml/cygwin/2015-03/msg00117.html
-------------- next part --------------
#include <signal.h>
#include <stdlib.h>
#include <string.h>

static int foo()
{
  void *p = malloc(10);
  memset(p, 0xca, 256);
  free(p);
  free(p);
}

static void
sighandler(int sig)
{
  foo();
}

int main()
{
  signal(SIGALRM, sighandler);

  alarm(1);

  sleep(10);
}
-------------- next part --------------
From 94391b7af06f6aec6fc02543b894b0963556118e Mon Sep 17 00:00:00 2001
From: Jon TURNEY <jon.turney@dronecode.org.uk>
Date: Mon, 9 Mar 2015 21:55:29 +0000
Subject: [PATCH] Teach stackinfo::walk() how to virtually unwind the tls
 sigstack

This improves how stackinfo::dumpstack() dumps _sigbe and sigdelayed frames

Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk>
---
 winsup/cygwin/ChangeLog     |  6 ++++++
 winsup/cygwin/exceptions.cc | 13 +++++++++++++
 winsup/cygwin/gendef        |  2 ++
 3 files changed, 21 insertions(+)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index d63b359..f0cbeed 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,9 @@
+2015-03-12  Jon TURNEY  <jon.turney@dronecode.org.uk>
+
+	* exceptions.cc (stack_info): Add sigstackptr member.
+	(walk): Unwind sigstackptr inside _sigbe and sigdelayed.
+	* gendef (_sigdelayed_end): Add symbol to mark end of sigdelayed.
+
 2015-03-11  Corinna Vinschen  <corinna@vinschen.de>
 
 	* include/cygwin/types.h: Include <sys/_timespec.h>
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 73de7e7..6035270 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -45,6 +45,8 @@ details. */
 #define CALL_HANDLER_RETRY_INNER 10
 
 char debugger_command[2 * NT_MAX_PATH + 20];
+extern u_char _sigbe;
+extern u_char _sigdelayed_end;
 
 static BOOL WINAPI ctrl_c_handler (DWORD);
 
@@ -277,6 +279,7 @@ class stack_info
 #ifdef __x86_64__
   CONTEXT c;
   UNWIND_HISTORY_TABLE hist;
+  __stack_t *sigstackptr;
 #endif
 public:
   STACKFRAME sf;		 /* For storing the stack information */
@@ -305,6 +308,7 @@ stack_info::init (PUINT_PTR framep, bool wantargs, PCONTEXT ctx)
       memset (&c, 0, sizeof c);
       c.ContextFlags = CONTEXT_ALL;
     }
+  sigstackptr = _my_tls.stackptr;
 #endif
   memset (&sf, 0, sizeof (sf));
   if (ctx)
@@ -340,6 +344,15 @@ stack_info::walk ()
   sf.AddrStack.Offset = c.Rsp;
   sf.AddrFrame.Offset = c.Rbp;
 
+  if ((c.Rip >= (DWORD64)&_sigbe) && (c.Rip < (DWORD64)&_sigdelayed_end))
+    {
+      /* _sigbe and sigdelayed don't have SEH unwinding data, so virtually
+         unwind the tls sigstack */
+      c.Rip = sigstackptr[-1];
+      sigstackptr--;
+      return 1;
+    }
+
   f = RtlLookupFunctionEntry (c.Rip, &imagebase, &hist);
   if (f)
     RtlVirtualUnwind (0, imagebase, c.Rip, f, &c, &hdl, &establisher, NULL);
diff --git a/winsup/cygwin/gendef b/winsup/cygwin/gendef
index ac411ca..01b8c39 100755
--- a/winsup/cygwin/gendef
+++ b/winsup/cygwin/gendef
@@ -327,6 +327,8 @@ sigdelayed:
 	xchgq	%r10,(%rsp)
 	ret
 	.seh_endproc
+_sigdelayed_end:
+	.global _sigdelayed_end
 
 # _cygtls::pop
 	.global _ZN7_cygtls3popEv
-- 
2.1.4



More information about the Cygwin-patches mailing list