Bug 201907 - JSClassRef leaks which referenced by JSGlobalObject::m_rareData::opaqueJSClassData
Summary: JSClassRef leaks which referenced by JSGlobalObject::m_rareData::opaqueJSClas...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Local Build
Hardware: All All
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2019-09-17 23:41 PDT by yusj_sw
Modified: 2019-09-19 16:50 PDT (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description yusj_sw 2019-09-17 23:41:09 PDT
// 1. C++ Code
class MyClass {
 public:
  MyClass() {}
  ~MyClass() {}
};

JSValueRef GetX(JSContextRef context, JSObjectRef object,
    JSStringRef propertyName, JSValueRef* exception) {
  // do nothing.
  return nullptr;
}

bool SetX(JSContextRef context, JSObjectRef object, JSStringRef propertyName,
    JSValueRef value, JSValueRef* exception) {
  return true;
}

JSStaticValue fields[] = {
  { "X", GetX, SetX, kJSPropertyAttributeNone },
  { 0, 0, 0, 0 }
};

void JSObjectFinalizeCallback(JSObjectRef object) {
  delete static_cast<MyClass*>(JSObjectGetPrivate(object));
}

JSValueRef CreateObjectCallback(JSContextRef context, JSObjectRef function,
    JSObjectRef thiz, size_t argc, const JSValueRef arguments[],
    JSValueRef* exception) {
  JSClassDefinition definition = kJSClassDefinitionEmpty;
  definition.attributes   = kJSClassAttributeNoAutomaticPrototype;
  definition.staticValues = fields;
  definition.finalize     = &JSObjectFinalizeCallback;
  JSClassRef clazz = JSClassCreate(&definition);
  JSObjectRef obj = JSObjectMake(context, clazz, new MyClass());
  JSClassRelease(clazz);
  return obj;
}

void Init(JSContxtRef context) {
  // register JS global function 'createMyObject()'
  JSStringRef name = JSStringCreateWithUTF8CString("createMyObject");
  JSObjectRef function = JSObjectMakeFunctionWithCallback(
      context, name, &CreateObjectCallback);
  JSObjectRef global = JSContextGetGlobalObject(context);
  JSObjectSetProperty(context, global, name, function,
                      kJSPropertyAttributeNone, nullptr);
  JSStringRelease(name);
}


// 2. JS Code
for (var i = 0; i < 100000; ++i) {
  createMyObject().X;
}
// %DoJavaScriptGC()%


// 3. Result
We have 100000 JSClassRef objects, they are all referenced by JSGlobalObject::m_rareData::opaqueJSClassData,
even though all the binding JS Objects have been GC-ed.
The bugly reference call stack is:

#0  WTF::ThreadSafeRefCountedBase::ref (this=0xe50a4120) at WTF/wtf/ThreadSafeRefCounted.h:44
#1  0xd334d3f2 in WTF::refIfNotNull<OpaqueJSClass> (ptr=0xe50a4120) at WTF/wtf/RefPtr.h:38
#2  0xd3347732 in WTF::RefPtr<OpaqueJSClass, WTF::DumbPtrTraits<OpaqueJSClass> >::RefPtr (this=0xe508bb60, ptr=0xe50a4120) at WTF/wtf/RefPtr.h:57
#3  0xd3346e9a in OpaqueJSClassContextData::OpaqueJSClassContextData (this=0xe508bb60, jsClass=0xe50a4120) at JavaScriptCore/API/JSClassRef.cpp:128
#4  0xd3347938 in make_unique<OpaqueJSClassContextData, JSC::VM&, OpaqueJSClass*> (...) at memory:3118
#5  OpaqueJSClass::contextData (this=0xe50a4120, exec=0xd64b0968) at JavaScriptCore/API/JSClassRef.cpp:154
#6  0xd3347b98 in OpaqueJSClass::staticValues (this=0xe50a4120, exec=0xd64b0968) at JavaScriptCore/API/JSClassRef.cpp:166
#7  0xd36e9704 in JSC::JSCallbackObject<JSC::JSDestructibleObject>::getOwnPropertySlot (object=0xcfc540a0, exec=0xd64b0968, propertyName=..., slot=...)
    at JavaScriptCore/API/JSCallbackObjectFunctions.h:193
#8  0xd335d184 in JSC::JSObject::getNonIndexPropertySlot (this=0xcfc540a0, exec=0xd64b0968, propertyName=..., slot=...)
    at JavaScriptCore/runtime/JSObjectInlines.h:155
#9  0xd335cc6e in JSC::JSObject::getPropertySlot<false> (this=0xcfc540a0, exec=0xd64b0968, propertyName=..., slot=...)
    at JavaScriptCore/runtime/JSObject.h:1425
#10 0xd3486442 in JSC::JSValue::getPropertySlot (this=0xd64b0870, exec=0xd64b0968, propertyName=..., slot=...)
    at JavaScriptCore/runtime/JSCJSValueInlines.h:912
#11 0xd347bab6 in JSC::JSValue::get (this=0xd64b0870, exec=0xd64b0968, propertyName=..., slot=...)
    at JavaScriptCore/runtime/JSCJSValueInlines.h:869
#12 0xd3949d12 in llint_slow_path_get_by_id (exec=0xd64b0968, pc=0xe50bbfe7) at JavaScriptCore/llint/LLIntSlowPaths.cpp:762


// 4. Possible Solution:
Change the type of JSGlobalObject::m_rareData::opaqueJSClassData from HashMap to WeakHashMap.
Comment 1 Radar WebKit Bug Importer 2019-09-19 16:50:11 PDT
<rdar://problem/55540351>