<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@lists.webkit.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>nham@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&, JSC::CodeBlockSet&) + 88
1 JavaScriptCore JSC::MachineThreads::gatherFromOtherThread(JSC::ConservativeRoots&, JSC::MachineThreads::Thread*, JSC::JITStubRoutineSet&, JSC::CodeBlockSet&) + 132
2 JavaScriptCore JSC::MachineThreads::gatherFromOtherThread(JSC::ConservativeRoots&, JSC::MachineThreads::Thread*, JSC::JITStubRoutineSet&, JSC::CodeBlockSet&) + 132
3 JavaScriptCore JSC::MachineThreads::gatherConservativeRoots(JSC::ConservativeRoots&, JSC::JITStubRoutineSet&, JSC::CodeBlockSet&, void*, int (&) [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<bmalloc::StaticMutex>&, unsigned long) + 36
1 JavaScriptCore bmalloc::Heap::allocateXLarge(std::__1::lock_guard<bmalloc::StaticMutex>&, unsigned long) + 20
2 JavaScriptCore bmalloc::Allocator::allocateXLarge(unsigned long) + 92
3 JavaScriptCore JSC::MachineThreads::gatherConservativeRoots(JSC::ConservativeRoots&, JSC::JITStubRoutineSet&, JSC::CodeBlockSet&, void*, void*, int (&) [48]) + 176
4 JavaScriptCore JSC::Heap::markRoots(double, void*, void*, int (&) [48]) + 384
5 JavaScriptCore JSC::Heap::collectImpl(JSC::HeapOperation, void*, void*, int (&) [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 <rdar://27607384> 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>