Segfault in _Unwind_* code called from pthread_exit
Andreas Tobler
andreast-list at fgznet.ch
Tue Oct 31 21:52:38 UTC 2017
On 31.10.17 22:36, Gerald Pfeifer wrote:
> On Tue, 31 Oct 2017, Andreas Tobler wrote:
>> Do we, FreeBSD'ers, want to have gcc unwind support on older than
>> FreeBSD 9.3 releases? I think the gcc folks do not care, but we are the
>> ones who might have an need for such a support?
>> @Gerald, do you have an opinion?
>
> Yes. No. :-)
>
> Those possibly still stuck on obsolete versions of FreeBSD don't
> need/want fancy new compilers and GCC 4.9 is still available for
> use and does not exhibit this issue, correct? (If it does, nobody
> reported any problems.)
It is limited to gcc >=5, gcc-4.9 does not have the
MD_FALLBACK_FRAME_STATE_FOR defined.
>> I can 'ifdef' the new code and in the 'else' case we fall back to
>> the already existing path.
>
> If it's "cheap", that might be nice.
Attached, the test is running on gcc trunk and gcc-6. gcc-6 is the last
one with java support and there we have quite extensive test cases which
really test for this MD_FALLBACK_FRAME_STATE_FOR macro. These test
cases, Throw_2 and co do pass. So I think the new bits should be fine.
Also some coming asan test cases do pass with this addition too.
> Thanks to the three of you - Tijl, Konstantin, and Andreas!
Gruss,
Andreas
-------------- next part --------------
Index: libgcc/config/i386/freebsd-unwind.h
===================================================================
--- libgcc/config/i386/freebsd-unwind.h (revision 254205)
+++ libgcc/config/i386/freebsd-unwind.h (working copy)
@@ -28,7 +28,10 @@
#include <sys/types.h>
#include <signal.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
#include <sys/ucontext.h>
+#include <sys/user.h>
#include <machine/sigframe.h>
#define REG_NAME(reg) sf_uc.uc_mcontext.mc_## reg
@@ -36,6 +39,39 @@
#ifdef __x86_64__
#define MD_FALLBACK_FRAME_STATE_FOR x86_64_freebsd_fallback_frame_state
+#ifdef KERN_PROC_SIGTRAMP
+ /* Newer versions of FreeBSD, > FreeBSD 9.3, provide a
+ kern.proc.sigtramp.<pid> sysctl that returns the location of the
+ signal trampoline. We use this information to find out if we're in
+ a trampoline or not.
+ */
+static int
+x86_64_outside_sigtramp_range (unsigned char *pc)
+{
+ static int sigtramp_range_determined = 0;
+ static unsigned char *sigtramp_start, *sigtramp_end;
+
+ if (sigtramp_range_determined == 0)
+ {
+ struct kinfo_sigtramp kst = {0};
+ size_t len = sizeof (kst);
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_SIGTRAMP, getpid() };
+
+ sigtramp_range_determined = 1;
+ if (sysctl (mib, 4, &kst, &len, NULL, 0) == 0)
+ {
+ sigtramp_range_determined = 2;
+ sigtramp_start = kst.ksigtramp_start;
+ sigtramp_end = kst.ksigtramp_end;
+ }
+ }
+ if (sigtramp_range_determined < 2) /* sysctl failed if < 2 */
+ return 1;
+
+ return (pc < sigtramp_start || pc >= sigtramp_end);
+}
+#endif
+
static _Unwind_Reason_Code
x86_64_freebsd_fallback_frame_state
(struct _Unwind_Context *context, _Unwind_FrameState *fs)
@@ -43,6 +79,7 @@
struct sigframe *sf;
long new_cfa;
+#ifndef KERN_PROC_SIGTRAMP
/* 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
@@ -62,12 +99,15 @@
&& *(unsigned int *)(context->ra + 8) == 0x01a1c0c7
&& *(unsigned int *)(context->ra + 12) == 0x050f0000 ))
return _URC_END_OF_STACK;
+#else
+ if (x86_64_outside_sigtramp_range(context->ra))
+ return _URC_END_OF_STACK;
+#endif
sf = (struct sigframe *) context->cfa;
new_cfa = sf->REG_NAME(rsp);
fs->regs.cfa_how = CFA_REG_OFFSET;
- /* Register 7 is rsp */
- fs->regs.cfa_reg = 7;
+ fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__;
fs->regs.cfa_offset = new_cfa - (long) context->cfa;
/* The SVR4 register numbering macros aren't usable in libgcc. */
More information about the freebsd-current
mailing list