Re: Segfault in _Unwind_* code called from pthread_exit

From: Konstantin Belousov <kostikbel_at_gmail.com>
Date: Thu, 24 Aug 2017 18:42:35 +0300
On Wed, Aug 23, 2017 at 04:37:07PM +0200, Tijl Coosemans wrote:
> Hi,
> 
> The following program segfaults for me on amd64 when linked like this:
> 
> cc -o test test.c -lpthread -L/usr/local/lib/gcc5 -lgcc_s -rpath /usr/local/lib/gcc5
> 
> --------------------------------
> #include <pthread.h>
> #include <stdio.h>
> 
> void *
> thr( void *arg ) {
> 	return( NULL );
> }
> 
> int
> main( void ) {
> 	pthread_t thread;
> 
> 	for( int i = 1; i < 20; i++ ) {
> 		fprintf( stderr, "%d\n", i );
> 		pthread_create( &thread, NULL, thr, NULL );
> 		pthread_join( thread, NULL );
> 	}
> 	return( 0 );
> }
> --------------------------------
> 
> The backtrace looks like this:
> 
> Thread 7 received signal SIGSEGV, Segmentation fault.
> [Switching to LWP 100511 of process 1886]
> uw_frame_state_for (context=context_at_entry=0x7fffdfffddc0, 
>     fs=fs_at_entry=0x7fffdfffdb10)
>     at /usr/ports/lang/gcc5/work/gcc-5.4.0/libgcc/unwind-dw2.c:1249
> 1249	/usr/ports/lang/gcc5/work/gcc-5.4.0/libgcc/unwind-dw2.c: No such file or directory.
> (gdb) bt
> #0  uw_frame_state_for (context=context_at_entry=0x7fffdfffddc0, 
>     fs=fs_at_entry=0x7fffdfffdb10)
>     at /usr/ports/lang/gcc5/work/gcc-5.4.0/libgcc/unwind-dw2.c:1249
> #1  0x0000000800a66ecb in _Unwind_ForcedUnwind_Phase2 (
>     exc=exc_at_entry=0x800658730, context=context_at_entry=0x7fffdfffddc0)
>     at /usr/ports/lang/gcc5/work/gcc-5.4.0/libgcc/unwind.inc:155
> #2  0x0000000800a67200 in _Unwind_ForcedUnwind (exc=0x800658730, 
>     stop=0x8008428b0 <thread_unwind_stop>, stop_argument=0x0)
>     at /usr/ports/lang/gcc5/work/gcc-5.4.0/libgcc/unwind.inc:207
> #3  0x0000000800842224 in _Unwind_ForcedUnwind (ex=0x800658730, 
>     stop_func=0x8008428b0 <thread_unwind_stop>, stop_arg=0x0)
>     at /usr/src/lib/libthr/thread/thr_exit.c:106
> #4  0x000000080084269f in thread_unwind ()
>     at /usr/src/lib/libthr/thread/thr_exit.c:172
> #5  0x00000008008424d6 in _pthread_exit_mask (status=0x0, mask=0x0)
>     at /usr/src/lib/libthr/thread/thr_exit.c:254
> #6  0x0000000800842359 in _pthread_exit (status=0x0)
>     at /usr/src/lib/libthr/thread/thr_exit.c:206
> #7  0x000000080082ccb1 in thread_start (curthread=0x800658500)
>     at /usr/src/lib/libthr/thread/thr_create.c:289
> #8  0x00007fffdfdfe000 in ?? ()
> Backtrace stopped: Cannot access memory at address 0x7fffdfffe000
> 
> 
> It happens with gcc6 as well, but not with base libgcc_s.
> Can anyone reproduce this?  Have there been any changes to stack
> unwinding recently (last few months)?

I can reproduce this, and there was a change in gcc unwinder, it seems.
Below is a patch which I did not even compiled.  Still, it should give
an idea how it might be approached.  The patch is against gcc head.

Index: libgcc/config/i386/freebsd-unwind.h
===================================================================
--- libgcc/config/i386/freebsd-unwind.h	(revision 251293)
+++ libgcc/config/i386/freebsd-unwind.h	(working copy)
_at__at_ -28,6 +28,8 _at__at_ see the files COPYING3 and COPYING.RUNTIME respect
 
 #include <sys/types.h>
 #include <signal.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
 #include <sys/ucontext.h>
 #include <machine/sigframe.h>
 
_at__at_ -42,7 +44,29 _at__at_ x86_64_freebsd_fallback_frame_state
 {
   struct sigframe *sf;
   long new_cfa;
+#ifdef KERN_PROC_SIGTRAMP
+  static long sigtramp_addr = 0;
 
+  if (sigtramp_addr == 0) {
+    struct kinfo_sigtramp kst;
+    int error, mib[4];
+    size_t len;
+
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_SIGTRAMP;
+    mib[3] = getpid();
+    len = sizeof(kst);
+    error = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &kst, &len, NULL, 0);
+    if (error == 0)
+      sigtramp_addr = kst.ksigtramp_start;
+  }
+
+  if (sigtramp_addr != 0 && (uintptr_t)(context->ra) == sigtramp_addr)
+    ;
+  else
+#endif
+
   /* Prior to FreeBSD 9, the signal trampoline was located immediately
      before the ps_strings.  To support non-executable stacks on AMD64,
      the sigtramp was moved to a shared page for FreeBSD 9.  Unfortunately
Received on Thu Aug 24 2017 - 13:42:42 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:41:13 UTC