Bug 131682 - Reproducible crash in JavaScriptCore: JSObjectMakeArray()
Summary: Reproducible crash in JavaScriptCore: JSObjectMakeArray()
Status: RESOLVED INVALID
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: Mac (Intel) OS X 10.9
: P1 Critical
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-04-15 11:23 PDT by Alexander Meißner
Modified: 2015-03-30 13:21 PDT (History)
2 users (show)

See Also:


Attachments
Source code to reproduce the crash (2.98 KB, text/plain-text)
2014-04-15 11:27 PDT, Alexander Meißner
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Meißner 2014-04-15 11:23:41 PDT
Reproducible crash in JavaScriptCore:
JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0);

The attached source code crashes every time the same way.
No JS exception is thrown and there are serval ways to manipulate when it crashes, but it always crashes in JSObjectMakeArray().
I'm not sure if I'm doing something fundamentally wrong or if it really is a bug in JavaScriptCore its self.
The circumstances which are needed to reproduce the crash are very odd and I randomly came across this bug by implementing a linear algebra JS interface for a separate project.


Call stack:
#0	0x00000001018d7057 in JSC::StructureIDTable::get(unsigned int) [inlined] at WebKit/Source/JavaScriptCore/runtime/StructureIDTable.h:86
#1	0x00000001018d7050 in JSC::JSCell::structure(JSC::VM&) const [inlined] at WebKit/Source/JavaScriptCore/runtime/JSCellInlines.h:104
#2	0x00000001018d7050 in JSC::JSCell::methodTable() const [inlined] at WebKit/Source/JavaScriptCore/runtime/JSCellInlines.h:191
#3	0x00000001018d7036 in toJS(JSC::ExecState*, OpaqueJSValue const*) [inlined] at WebKit/Source/JavaScriptCore/API/APICast.h:81
#4	0x00000001018d702e in JSObjectMakeArray at WebKit/Source/JavaScriptCore/API/JSObjectRef.cpp:178


Tested r167020: One built by my self and also the JavaScriptCore.framework of WebKit nightly
MacBook Pro Retina, Mid 2012, 64-Bit, MacOS 10.8.5 and another one (identical hardware) but with MacOS 10.9


All of the following ways stop the test from crashing or change the iteration it crashes:

1. context = JSGlobalContextCreate(NULL); //instead of JSClassCreate(&kJSClassDefinitionEmpty)

2. not adding the property "test" to the contexts global object

3. using stack memory instead of heap for the valueArray passed to JSObjectMakeArray() like:
JSValueRef valueArray[4];
or
JSValueRef* valueArray = (JSValueRef*)alloca(sizeof(JSValueRef)*4);

4. adding another than 3 or 4 properties to the vector instances
0 properties: All Iterations
1 property: All Iterations
2 properties: All Iterations
3 properties: 326 Iterations
4 properties: 285 Iterations
5 properties: All Iterations
6 properties: All Iterations

5. Not passing a JSClassRef to:
JSObjectRef instance = JSObjectMake(context, NULL, NULL);

6. Creating less than 4 instances of the vector class in one iteration:
0 to 3 instances per iteration: All Iterations
4 instances per iteration: 326 Iterations
5 instances per iteration: 575 Iterations
6 instances per iteration: 217 Iterations
7 instances per iteration: 186 Iterations
8 instances per iteration: 163 Iterations

7. Adjusting the argumentCount parameter of JSObjectMakeArray() to the actual count of instances per iteration changes the behavior too

But not a single one of them is a work around as I need the complete functionality of JavaScriptCore.
Comment 1 Alexander Meißner 2014-04-15 11:27:56 PDT
Created attachment 229382 [details]
Source code to reproduce the crash

When compiling and running the code, be sure to link against the JavaScriptCore.framework of WebKit Nightly not the one of your system

You can check that by using: otool -L [executable]

Which should show something like:
@executable_path/JavaScriptCore.framework/Versions/A/JavaScriptCore
instead of:
/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore
Comment 2 Adam 2015-01-24 08:44:55 PST
I reproduced this on my machine (Mid-2011 Mini, OS X 10.10.1) Using Webkit svn rev 176947.  I'm interested in this as it seems very similar to a bug I reported to Apple rdar://19378158 (http://openradar.appspot.com/radar?id=6174800997253120)
Comment 3 Adam 2015-01-25 18:23:05 PST
Actually, now I think it might be just an issue with the example. I can't claim to know anything about how JavaScript works, but I think the newly created objects aren't on the stack, so the garbage collector doesn't know about them, so occasionally an object just gets deallocated. Doing something like this fixes the issue:

JSValueRef a = newVectorInstance()
valueArray[0] = a;
...etc...

Does anyone know if that's right or if there is another way to keep an object from being collected? (JSValueProtect/JSValueUnprotect also works, but it seems like that is if you want the objects to be global).
Comment 4 Alexander Meißner 2015-01-26 05:25:24 PST
(In reply to comment #3)

This is actually more the way C/C++ works that matters than the way JavaScript works.

The difference is that

JSValueRef a = newVectorInstance();
valueArray[0] = a;

orders the compiler to use the stack, while

valueArray[0] = newVectorInstance();

is a temporary value which could be held in registers.
But this is already known to be part of the bug,
using the stack is some kind of work around:

JSValueRef* valueArray = (JSValueRef*)alloca(sizeof(JSValueRef)*4);


I suspect that the problem might be in the Construction/Destruction of JSValue (as that would be stack related)
or a memory access in the heap that goes wrong, caused by a early delete/free of memory.
Comment 5 Geoffrey Garen 2015-03-30 13:21:28 PDT
>     JSValueRef* valueArray = new JSValueRef[8];

It's not valid to put a JSValueRef in the heap without first calling JSValueProtect.

The garbage collector will automatically scan JSValueRefs on the stack, but once you put the JSValueRef into the heap like this, you need to use explicit reference counting through JSValueProtect and JSValueUnprotect.