Title: [201394] trunk
Revision
201394
Author
[email protected]
Date
2016-05-25 12:08:02 -0700 (Wed, 25 May 2016)

Log Message

[Font Loading] ASSERT if calling FontFace.loaded twice with a garbage collection between them
https://bugs.webkit.org/show_bug.cgi?id=158015

Reviewed by Darin Adler.

Source/WebCore:

The following scenario may occur:

1. We create a FontFace object
2. We create an associated JSFontFace object
3. We start loading the FontFace, which causes an extra ref to hang around until loading finishes
4. _javascript_ calls the "loaded" attribute on the FontFace, which saves a promise inside the FontFace
5. The FontFace goes out of scope in _javascript_
6. A garbage collection occurs, causing us to delete the JSFontFace object
7. _javascript_ then encounters the FontFace object without first going through a reference to a JSFontFace.
It can do this via iterating through a FontFaceSet. We respond to this situation by creating a new
JSFontFace object and associating it with the existing FontFace.
8. _javascript_ calls the "loaded" attribute

In this situation, the newer JSFontFace object is out of sync with the older FontFace object. In
particular, the FontFace has a saved promise, but the JSFontFace doesn't know about it. Therefore,
the JSFontFace should be flexible to the presence of this member.

Test: fast/text/font-face-crash-2.html

* bindings/js/JSDOMPromise.h:
(WebCore::DOMPromise::deferredWrapper):
* bindings/js/JSFontFaceCustom.cpp:
(WebCore::JSFontFace::loaded):
* css/FontFace.h:

LayoutTests:

* fast/text/font-face-crash-2-expected.txt: Added.
* fast/text/font-face-crash-2.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (201393 => 201394)


--- trunk/LayoutTests/ChangeLog	2016-05-25 19:04:47 UTC (rev 201393)
+++ trunk/LayoutTests/ChangeLog	2016-05-25 19:08:02 UTC (rev 201394)
@@ -1,3 +1,13 @@
+2016-05-25  Myles C. Maxfield  <[email protected]>
+
+        [Font Loading] ASSERT if calling FontFace.loaded twice with a garbage collection between them
+        https://bugs.webkit.org/show_bug.cgi?id=158015
+
+        Reviewed by Darin Adler.
+
+        * fast/text/font-face-crash-2-expected.txt: Added.
+        * fast/text/font-face-crash-2.html: Added.
+
 2016-05-25  Antti Koivisto  <[email protected]>
 
         Shadow DOM: RenderTreePosition should determine if element has display:contents from new style

Added: trunk/LayoutTests/fast/text/font-face-crash-2-expected.txt (0 => 201394)


--- trunk/LayoutTests/fast/text/font-face-crash-2-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/text/font-face-crash-2-expected.txt	2016-05-25 19:08:02 UTC (rev 201394)
@@ -0,0 +1 @@
+This test makes sure that if we construct two JSFontFaces for the same FontFace, and call "loaded" on both of them, that there is no ASSERT.
Property changes on: trunk/LayoutTests/fast/text/font-face-crash-2-expected.txt
___________________________________________________________________

Added: svn:keywords

Added: svn:eol-style

Added: trunk/LayoutTests/fast/text/font-face-crash-2.html (0 => 201394)


--- trunk/LayoutTests/fast/text/font-face-crash-2.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/font-face-crash-2.html	2016-05-25 19:08:02 UTC (rev 201394)
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+(function() {
+    var font = new FontFace("WebFont", "url('notarealfont')", {});
+    font.loaded;
+    font.load();
+    document.fonts.add(font);
+})();
+if (window.GCController)
+    GCController.collect();
+document.fonts.forEach(function(font) {
+    if (font.family == "WebFont")
+        font.loaded;
+});
+</script>
+This test makes sure that if we construct two JSFontFaces for the same FontFace, and call "loaded" on both of them, that there is no ASSERT.
+</body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (201393 => 201394)


--- trunk/Source/WebCore/ChangeLog	2016-05-25 19:04:47 UTC (rev 201393)
+++ trunk/Source/WebCore/ChangeLog	2016-05-25 19:08:02 UTC (rev 201394)
@@ -1,3 +1,35 @@
+2016-05-25  Myles C. Maxfield  <[email protected]>
+
+        [Font Loading] ASSERT if calling FontFace.loaded twice with a garbage collection between them
+        https://bugs.webkit.org/show_bug.cgi?id=158015
+
+        Reviewed by Darin Adler.
+
+        The following scenario may occur:
+
+        1. We create a FontFace object
+        2. We create an associated JSFontFace object
+        3. We start loading the FontFace, which causes an extra ref to hang around until loading finishes
+        4. _javascript_ calls the "loaded" attribute on the FontFace, which saves a promise inside the FontFace
+        5. The FontFace goes out of scope in _javascript_
+        6. A garbage collection occurs, causing us to delete the JSFontFace object
+        7. _javascript_ then encounters the FontFace object without first going through a reference to a JSFontFace.
+        It can do this via iterating through a FontFaceSet. We respond to this situation by creating a new
+        JSFontFace object and associating it with the existing FontFace.
+        8. _javascript_ calls the "loaded" attribute
+
+        In this situation, the newer JSFontFace object is out of sync with the older FontFace object. In
+        particular, the FontFace has a saved promise, but the JSFontFace doesn't know about it. Therefore,
+        the JSFontFace should be flexible to the presence of this member.
+
+        Test: fast/text/font-face-crash-2.html
+
+        * bindings/js/JSDOMPromise.h:
+        (WebCore::DOMPromise::deferredWrapper):
+        * bindings/js/JSFontFaceCustom.cpp:
+        (WebCore::JSFontFace::loaded):
+        * css/FontFace.h:
+
 2016-05-25  Antti Koivisto  <[email protected]>
 
         Shadow DOM: RenderTreePosition miscomputed when display:contents value changes

Modified: trunk/Source/WebCore/bindings/js/JSDOMPromise.h (201393 => 201394)


--- trunk/Source/WebCore/bindings/js/JSDOMPromise.h	2016-05-25 19:04:47 UTC (rev 201393)
+++ trunk/Source/WebCore/bindings/js/JSDOMPromise.h	2016-05-25 19:08:02 UTC (rev 201394)
@@ -165,6 +165,8 @@
 
     template<typename... ErrorType> void reject(ErrorType&&... error) { m_wrapper.reject(std::forward<ErrorType>(error)...); }
 
+    DeferredWrapper& deferredWrapper() { return m_wrapper; }
+
 private:
     DeferredWrapper m_wrapper;
 };

Modified: trunk/Source/WebCore/bindings/js/JSFontFaceCustom.cpp (201393 => 201394)


--- trunk/Source/WebCore/bindings/js/JSFontFaceCustom.cpp	2016-05-25 19:04:47 UTC (rev 201393)
+++ trunk/Source/WebCore/bindings/js/JSFontFaceCustom.cpp	2016-05-25 19:08:02 UTC (rev 201394)
@@ -38,9 +38,12 @@
 JSC::JSValue JSFontFace::loaded(JSC::ExecState& state) const
 {
     if (!m_loaded) {
-        DeferredWrapper promise(&state, globalObject(), JSC::JSPromiseDeferred::create(&state, globalObject()));
-        m_loaded.set(state.vm(), this, promise.promise());
-        wrapped().registerLoaded(WTFMove(promise));
+        if (!wrapped().promise()) {
+            DeferredWrapper promise(&state, globalObject(), JSC::JSPromiseDeferred::create(&state, globalObject()));
+            m_loaded.set(state.vm(), this, promise.promise());
+            wrapped().registerLoaded(WTFMove(promise));
+        } else
+            m_loaded.set(state.vm(), this, wrapped().promise().value().deferredWrapper().promise());
     }
     return m_loaded.get();
 }

Modified: trunk/Source/WebCore/css/FontFace.h (201393 => 201394)


--- trunk/Source/WebCore/css/FontFace.h	2016-05-25 19:04:47 UTC (rev 201393)
+++ trunk/Source/WebCore/css/FontFace.h	2016-05-25 19:08:02 UTC (rev 201394)
@@ -66,6 +66,7 @@
     LoadStatus status() const;
 
     typedef DOMPromise<FontFace&> Promise;
+    Optional<Promise>& promise() { return m_promise; }
     void registerLoaded(Promise&&);
 
     void load();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to