<html>
    <head>
      <base href="https://bugs.webkit.org/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Crash in JavaScriptCore GC when using JSC on dispatch queues"
   href="https://bugs.webkit.org/show_bug.cgi?id=160337">160337</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Crash in JavaScriptCore GC when using JSC on dispatch queues
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>WebKit
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>Other
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>iOS
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>iOS 9.3
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>Normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P2
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>JavaScriptCore
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>webkit-unassigned&#64;lists.webkit.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>nham&#64;fb.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>We recently enabled the use of JSC APIs in our app from dispatch queues. This lead to a number of crashes in the JSC GC timer so we had to remove this feature from our app. This implies that it's not safe to use JSC on a dispatch queue.

The crashing stack looks like this on iOS 8 (EXC_BAD_ADDRESS at 0x0):

  Thread #15 Crashed:
  0 JavaScriptCore JSC::ConservativeRoots::add(void*, void*, JSC::JITStubRoutineSet&amp;, JSC::CodeBlockSet&amp;) + 88
  1 JavaScriptCore JSC::MachineThreads::gatherFromOtherThread(JSC::ConservativeRoots&amp;, JSC::MachineThreads::Thread*, JSC::JITStubRoutineSet&amp;, JSC::CodeBlockSet&amp;) + 132
  2 JavaScriptCore JSC::MachineThreads::gatherFromOtherThread(JSC::ConservativeRoots&amp;, JSC::MachineThreads::Thread*, JSC::JITStubRoutineSet&amp;, JSC::CodeBlockSet&amp;) + 132
  3 JavaScriptCore JSC::MachineThreads::gatherConservativeRoots(JSC::ConservativeRoots&amp;, JSC::JITStubRoutineSet&amp;, JSC::CodeBlockSet&amp;, void*, int (&amp;) [48]) + 384
  4 JavaScriptCore JSC::Heap::markRoots(double) + 432
  5 JavaScriptCore JSC::Heap::collect(JSC::HeapOperation) + 376
  6 JavaScriptCore JSC::GCActivityCallback::doWork() + 144
  7 JavaScriptCore JSC::HeapTimer::timerDidFire(__CFRunLoopTimer*, void*) + 196
  8 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 24
  9 CoreFoundation __CFRunLoopDoTimer + 884
  10 CoreFoundation __CFRunLoopRun + 1368
  11 CoreFoundation CFRunLoopRunSpecific + 392
  12 Facebook +[RCTJSCExecutor runRunLoopThread] (RCTJSCExecutor.mm:280)
  13 Foundation __NSThread__main__ + 1068
  14 libsystem_pthread.dylib _pthread_body + 160
  15 libsystem_pthread.dylib _pthread_start + 156
  16 libsystem_pthread.dylib thread_start + 0

Basically, this is the marker segfaulting on trying to dereference a stack pointer of 0x0 for the target thread. (For this crash, we actually have a dump of the entire state of the stack in this crash, and were able to walk up the stack and find the Thread::Registers instance right on the stack clearly showing a SP of 0x0.)

The crashing stack looks like this on iOS 9 (EXC_BAD_ACCESS at 0xbbadbeef):

  Thread #11 Crashed:
  0 JavaScriptCore bmalloc::Heap::allocateXLarge(std::__1::lock_guard&lt;bmalloc::StaticMutex&gt;&amp;, unsigned long) + 36
  1 JavaScriptCore bmalloc::Heap::allocateXLarge(std::__1::lock_guard&lt;bmalloc::StaticMutex&gt;&amp;, unsigned long) + 20
  2 JavaScriptCore bmalloc::Allocator::allocateXLarge(unsigned long) + 92
  3 JavaScriptCore JSC::MachineThreads::gatherConservativeRoots(JSC::ConservativeRoots&amp;, JSC::JITStubRoutineSet&amp;, JSC::CodeBlockSet&amp;, void*, void*, int (&amp;) [48]) + 176
  4 JavaScriptCore JSC::Heap::markRoots(double, void*, void*, int (&amp;) [48]) + 384
  5 JavaScriptCore JSC::Heap::collectImpl(JSC::HeapOperation, void*, void*, int (&amp;) [48]) + 612
  6 JavaScriptCore JSC::Heap::collect(JSC::HeapOperation) + 92
  7 JavaScriptCore JSC::GCActivityCallback::doWork() + 88
  8 JavaScriptCore JSC::HeapTimer::timerDidFire(__CFRunLoopTimer*, void*) + 216
  9 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 24
  10 CoreFoundation __CFRunLoopDoTimer + 880
  11 CoreFoundation __CFRunLoopRun + 1516
  12 CoreFoundation CFRunLoopRunSpecific + 380
  13 Facebook +[RCTJSCExecutor runRunLoopThread] (RCTJSCExecutor.mm:280)
  14 Foundation __NSThread__start__ + 996
  15 libsystem_pthread.dylib _pthread_body + 152
  16 libsystem_pthread.dylib _pthread_start + 152
  17 libsystem_pthread.dylib thread_start + 0

Basically, this is bmalloc crashing on purpose because vm_allocate can't allocate a large enough contiguous region to hold the target thread's stack, presumably because JSC thinks the stack is ginormous due to it having a SP of 0x0.

It looks like the basic issue here is that JSC uses thread_get_state to the the stack pointer of the target thread. Unfortunately, thread_get_state sometimes returns a SP of 0x0 for a thread. See &lt;rdar://27607384&gt; and <a href="https://openradar.appspot.com/27607384">https://openradar.appspot.com/27607384</a> for more details. Basically, when the target thread is a dispatch queue thread that's just about to run with this call stack:

  Thread #32:
  0 libsystem_pthread.dylib start_wqthread + 0

then thread_get_state may return 0x0 for the SP, causing the crashes in JSC GC outlined above.

It's unclear to me whether this is actually a kernel bug or a JSC bug, but it seems like it might be a good idea for JSC to be defensive against a SP of 0x0 and have it abort marking if a thread is in this state. Additionally, it seems like MachineStackMarker.cpp should do some sort of sanity check on the size of the stack and not try to allocate a ginormous buffer to hold a thread's stack. For instance, on iOS I believe the maximum size of a stack is 1 MB, so JSC should never be allocating more than that amount of space to hold a single thread's stack.</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are the assignee for the bug.</li>
      </ul>
    </body>
</html>