Title: [122198] trunk/Source/WebCore
Revision
122198
Author
[email protected]
Date
2012-07-10 00:08:53 -0700 (Tue, 10 Jul 2012)

Log Message

Threadsafety issues in WebScriptObject
https://bugs.webkit.org/show_bug.cgi?id=90849

Reviewed by Filip Pizlo.

WebScriptObject maintains a NSMap of wrapper objects. A race condition exists
between a wrapper being retrieved from the map, and being released - if the
final release on an object is called between a call to getJSWrapper and the
subsequent retain, we may end up with a stale object reference.

We can make this safe by hoisting the removal from the map from delloc up into
release (if the retainCount is 1), and locking release against retrieval from
the map. Since release may be called from another thread, and NSMap is not
threadsafe, we'd better lock around all access to the map (this fix already
necessitates get & remove to be locked, so this just adds 'add', too).

* bindings/objc/WebScriptObject.mm:
(WebCore::createJSWrapper):
    - lock around getJSWrapper, retain.
(-[WebScriptObject _setImp:originRootObject:rootObject:]):
    - lock around addJSWrapper.
(-[WebScriptObject release]):
    - Added; removeJSWrapper for last release, lock & synchronized vs. getJSWrapper.
(-[WebScriptObject dealloc]):
    - removeJSWrapper call hoisted into release.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (122197 => 122198)


--- trunk/Source/WebCore/ChangeLog	2012-07-10 06:42:40 UTC (rev 122197)
+++ trunk/Source/WebCore/ChangeLog	2012-07-10 07:08:53 UTC (rev 122198)
@@ -1,3 +1,31 @@
+2012-07-09  Gavin Barraclough  <[email protected]>
+
+        Threadsafety issues in WebScriptObject
+        https://bugs.webkit.org/show_bug.cgi?id=90849
+
+        Reviewed by Filip Pizlo.
+
+        WebScriptObject maintains a NSMap of wrapper objects. A race condition exists
+        between a wrapper being retrieved from the map, and being released - if the
+        final release on an object is called between a call to getJSWrapper and the
+        subsequent retain, we may end up with a stale object reference.
+
+        We can make this safe by hoisting the removal from the map from delloc up into
+        release (if the retainCount is 1), and locking release against retrieval from
+        the map. Since release may be called from another thread, and NSMap is not
+        threadsafe, we'd better lock around all access to the map (this fix already
+        necessitates get & remove to be locked, so this just adds 'add', too).
+
+        * bindings/objc/WebScriptObject.mm:
+        (WebCore::createJSWrapper):
+            - lock around getJSWrapper, retain.
+        (-[WebScriptObject _setImp:originRootObject:rootObject:]):
+            - lock around addJSWrapper.
+        (-[WebScriptObject release]):
+            - Added; removeJSWrapper for last release, lock & synchronized vs. getJSWrapper.
+        (-[WebScriptObject dealloc]):
+            - removeJSWrapper call hoisted into release.
+
 2012-07-09  Christophe Dumez  <[email protected]>
 
         [EFL] Battery status code needs refactoring to be reused in WebKit2

Modified: trunk/Source/WebCore/bindings/objc/WebScriptObject.mm (122197 => 122198)


--- trunk/Source/WebCore/bindings/objc/WebScriptObject.mm	2012-07-10 06:42:40 UTC (rev 122197)
+++ trunk/Source/WebCore/bindings/objc/WebScriptObject.mm	2012-07-10 07:08:53 UTC (rev 122198)
@@ -84,6 +84,9 @@
 
 id createJSWrapper(JSC::JSObject* object, PassRefPtr<JSC::Bindings::RootObject> origin, PassRefPtr<JSC::Bindings::RootObject> root)
 {
+    // NSMap is not thread safe, hold the JSC API lock; also synchronize this vs. release.
+    JSC::JSLockHolder holder(JSDOMWindowBase::commonJSGlobalData());
+
     if (id wrapper = getJSWrapper(object))
         return [[wrapper retain] autorelease];
     return [[[WebScriptObject alloc] _initWithJSObject:object originRootObject:origin rootObject:root] autorelease];
@@ -145,6 +148,9 @@
     _private->rootObject = rootObject.leakRef();
     _private->originRootObject = originRootObject.leakRef();
 
+    // NSMap is not thread safe, hold the JSC API lock.
+    JSC::JSLockHolder holder(JSDOMWindowBase::commonJSGlobalData());
+
     WebCore::addJSWrapper(self, imp);
 
     if (_private->rootObject)
@@ -223,14 +229,26 @@
     return jsCast<JSDOMWindowBase*>(root->globalObject())->allowsAccessFrom(_private->originRootObject->globalObject());
 }
 
+- (oneway void)release
+{
+    {
+        // NSMap is not thread safe, hold the JSC API lock; also synchronize this vs. getJSWrapper.
+        JSC::JSLockHolder holder(JSDOMWindowBase::commonJSGlobalData());
+
+        // If we're releasing the last reference to this object, remove if from the map,
+        // this will prevent this object from being returned by getJSWrapper.
+        if (_private->imp && [self retainCount] == 1)
+            WebCore::removeJSWrapper(_private->imp);
+    }
+
+    [super release];
+}
+
 - (void)dealloc
 {
     if (WebCoreObjCScheduleDeallocateOnMainThread([WebScriptObject class], self))
         return;
 
-    if (_private->imp)
-        WebCore::removeJSWrapper(_private->imp);
-
     if (_private->rootObject && _private->rootObject->isValid())
         _private->rootObject->gcUnprotect(_private->imp);
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to