Bug ID: 380269
           Summary: No multithreading in macOS Sierra (10.12)
           Product: valgrind
           Version: 3.12 SVN
          Platform: Mac OS X Disk Images
                OS: OS X
            Status: UNCONFIRMED
          Severity: normal
          Priority: NOR
         Component: general
  Target Milestone: ---

On macOS Sierra (10.12), if pthread_create is called while using valgrind the
program stops because of a SIGSEGV.

Snippet of the error:
==22190== Thread 2:
==22190== Invalid read of size 4
==22190==    at 0x10050790D: _pthread_body (in
==22190==    by 0x1005078FA: _pthread_start (in
==22190==    by 0x100507100: thread_start (in
==22190==  Address 0x18 is not stack'd, malloc'd or (recently) free'd

After some investigation, this bug comes when starting the new thread just
before the routine supplied to pthread_create is called. From my limited
understanding of assembly/macOS internals/valgrind, the thread tries to access
its thread-local storage (TLS) and fails because gs (the register that seems to
be allowed to it on macOS) is 0.

This means that valgrind interpret the problematic instruction
mov %gs:0x18,%ecx
lea [0+0x18],%ecx

While debbuging with gdb and lldb, with and without valgrind, I noted that gs
is always 0. So I don't know if it's technically possible but macOS Sierra
seems to hide the value of gs from the user, so when the binary is run without
valgrind the instruction loads the correct address even though gs is 0. When
running with valgrind, gs is taken directly from the register and is always 0
which triggers the bug.

The only solution I can see is guessing the address of the TLS and set it as
gs' value before going into pthread (in pthread_hijack), e.g.
diff --git a/coregrind/m_syswrap/syswrap-amd64-darwin.c
index c827bab..3c926cf 100644
--- a/coregrind/m_syswrap/syswrap-amd64-darwin.c
+++ b/coregrind/m_syswrap/syswrap-amd64-darwin.c
@@ -364,6 +364,10 @@ void pthread_hijack(Addr self, Addr kport, Addr func, Addr
    vex->guest_R9  = flags;
    vex->guest_RSP = sp;

+#if DARWIN_VERS >= DARWIN_10_12
+   vex->guest_GS_CONST = self;
    // Record thread's stack and Mach port and pthread struct
    tst->os_state.pthread = self;
    tst->os_state.lwpid = kport;

However, I wasn't able to guess a correct value for gs, and with the above fix
the program goes on but fails at the next pthread call, example with the above
fix applied:
==23490== Thread 2:
==23490== Invalid read of size 4
==23490==    at 0x100508538: _pthread_testcancel (in
==23490==    by 0x1002E0AD4: nanosleep (in /usr/lib/system/libsystem_c.dylib)
==23490==    by 0x1002E09D2: sleep (in /usr/lib/system/libsystem_c.dylib)
==23490==    by 0x100000E02: slavethread (pth_term_signal.c:27)
==23490==    by 0x1005079AE: _pthread_body (in
==23490==    by 0x1005078FA: _pthread_start (in
==23490==    by 0x100507100: thread_start (in
==23490==  Address 0x54485258 is not stack'd, malloc'd or (recently) free'd

Note that at this point, gdb shows gs value as 0x4ee4000 instead of
0x700004ee4000, so maybe the value is getting truncated at some point.

In previous versions of macOS, valgrind would set guest_GS_CONST in the
thread_fast_set_cthread_self (syswrap-darwin.c:9133) trap. However this
function is not called before going into the new thread, leaving an invalid
value for gs.

You are receiving this mail because:
You are watching all bug changes.

Reply via email to