1. Stanislav Sedov
  2. valgrind-freebsd
Issue #4 new

Crash in x86_freebsd_SUBST_FOR_sigreturn when cancelling a thread

Ryan Stone
created an issue

The attached testcase crashes when I run it under valgrind on i386 (on FreeBSD 8.2):

The crash is here (which happens when pthread_cancel tries to signal the second thread to exit):

vex x86->IR: unhandled instruction bytes: 0xF 0xB 0x90 0x55
==30076== valgrind: Unrecognised instruction at address 0x38044a3d.
==30076==    at 0x38044A3D: ??? (m_trampoline.S:698)
==30076==    by 0x69A29: ??? (in /lib/libthr.so.3)
==30076==    by 0x69B3B: pthread_cond_wait (in /lib/libthr.so.3)
==30076==    by 0x8048695: thread_start (sigreturn.c:12)
==30076==    by 0x616E4: ??? (in /lib/libthr.so.3)

m_trampoline.S:

VG_(x86_freebsd_SUBST_FOR_sigreturn):
        lea     0x14(%esp), %eax        /* args to sigreturn(ucontext_t *) */
        pushl   %eax
        pushl   %eax                    /* fake return addr */
/*      movl    0x44(%eax), %gs ; restore %gs, not done by sigreturn */
        movl    $__NR_fake_sigreturn, %eax
        int     $0x80
        ud2 /* line 698 */

I've done some digging and put some printfs in, and it appears that x86_freebsd_SUBST_FOR_sigreturn is using the wrong offset from %esp to find the ucontext_t*. I put one printf in build_sigframe just after synth_ucontext is called, and another two in PRE(sys_fake_sigreturn). The printfs demonstrate that fake_sigreturn is called with the wrong pointer (it's always off by 8 bytes for me).

synthesized ucontext 0x9F9FE590 (len=640)
sys_fake_sigreturn ( 0x9f9fe588 )
sys_fake_sigreturn (len=-1616908584 expected=640)

I can fix the crash by changing to:

lea     0x1c(%esp), %eax

But this sigreturn stuff looks like pure magic to me so I have no confidence that is actually the right fix.