Title: [137632] trunk
Revision
137632
Author
dbar...@mathscribe.com
Date
2012-12-13 11:48:26 -0800 (Thu, 13 Dec 2012)

Log Message

Heap-use-after-free in WebCore::RenderBlock::finishDelayUpdateScrollInfo
https://bugs.webkit.org/show_bug.cgi?id=103750

Reviewed by Tony Chang.

Source/WebCore:

MathML sometimes creates and destroys renderers for descendants during layout (or even to calculate
preferred logical widths), e.g. for operator stretching. RenderBlock::finishDelayUpdateScrollInfo
must therefore leave gDelayedUpdateScrollInfoSet intact as it iterates over it, so
RenderBlock::willBeDestroyed can call gDelayedUpdateScrollInfoSet->remove(this) effectively if needed.
This also prevents duplicate entries from being added to gDelayedUpdateScrollInfoSet.

Test: mathml/mo-stretch-crash.html

* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::startDelayUpdateScrollInfo):
    - Allow gDelayedUpdateScrollInfoSet to be non-null when gDelayUpdateScrollInfo is 0 during
      RenderBlock::finishDelayUpdateScrollInfo.
(WebCore::RenderBlock::finishDelayUpdateScrollInfo):
    - Remove blocks from gDelayedUpdateScrollInfoSet one at a time, waiting for each block until it is
      about to be updated.

LayoutTests:

* mathml/mo-stretch-crash-expected.txt: Added.
* mathml/mo-stretch-crash.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (137631 => 137632)


--- trunk/LayoutTests/ChangeLog	2012-12-13 19:46:13 UTC (rev 137631)
+++ trunk/LayoutTests/ChangeLog	2012-12-13 19:48:26 UTC (rev 137632)
@@ -1,3 +1,13 @@
+2012-12-13  David Barton  <dbar...@mathscribe.com>
+
+        Heap-use-after-free in WebCore::RenderBlock::finishDelayUpdateScrollInfo
+        https://bugs.webkit.org/show_bug.cgi?id=103750
+
+        Reviewed by Tony Chang.
+
+        * mathml/mo-stretch-crash-expected.txt: Added.
+        * mathml/mo-stretch-crash.html: Added.
+
 2012-12-13  Joanmarie Diggs  <jdi...@igalia.com>
 
         [GTK] accessibiltiy/aria-hidden.html is failing

Added: trunk/LayoutTests/mathml/mo-stretch-crash-expected.txt (0 => 137632)


--- trunk/LayoutTests/mathml/mo-stretch-crash-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/mathml/mo-stretch-crash-expected.txt	2012-12-13 19:48:26 UTC (rev 137632)
@@ -0,0 +1,2 @@
+This test passes if it does not crash.
+

Added: trunk/LayoutTests/mathml/mo-stretch-crash.html (0 => 137632)


--- trunk/LayoutTests/mathml/mo-stretch-crash.html	                        (rev 0)
+++ trunk/LayoutTests/mathml/mo-stretch-crash.html	2012-12-13 19:48:26 UTC (rev 137632)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<q id=quote></q>
+<dd id=dd>
+<body id=body>
+    <style>
+        dd, q, mfenced, div {
+            width: 7px;
+            overflow-y: auto;
+            padding-left: 100%;
+        }
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        body.contentEditable = "true";
+        function crash() {
+            mfenced = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mfenced");
+            div = document.createElement("div");
+            mfenced.appendChild(div);
+            dd.appendChild(mfenced);
+            body.style.display = "-webkit-flex";
+            div.appendChild(quote);
+        }
+        window.addEventListener("load", crash, false);
+    </script>
+
+This test passes if it does not crash.
+</body>
+</dd>

Modified: trunk/Source/WebCore/ChangeLog (137631 => 137632)


--- trunk/Source/WebCore/ChangeLog	2012-12-13 19:46:13 UTC (rev 137631)
+++ trunk/Source/WebCore/ChangeLog	2012-12-13 19:48:26 UTC (rev 137632)
@@ -1,3 +1,26 @@
+2012-12-13  David Barton  <dbar...@mathscribe.com>
+
+        Heap-use-after-free in WebCore::RenderBlock::finishDelayUpdateScrollInfo
+        https://bugs.webkit.org/show_bug.cgi?id=103750
+
+        Reviewed by Tony Chang.
+
+        MathML sometimes creates and destroys renderers for descendants during layout (or even to calculate
+        preferred logical widths), e.g. for operator stretching. RenderBlock::finishDelayUpdateScrollInfo
+        must therefore leave gDelayedUpdateScrollInfoSet intact as it iterates over it, so
+        RenderBlock::willBeDestroyed can call gDelayedUpdateScrollInfoSet->remove(this) effectively if needed.
+        This also prevents duplicate entries from being added to gDelayedUpdateScrollInfoSet.
+
+        Test: mathml/mo-stretch-crash.html
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::startDelayUpdateScrollInfo):
+            - Allow gDelayedUpdateScrollInfoSet to be non-null when gDelayUpdateScrollInfo is 0 during
+              RenderBlock::finishDelayUpdateScrollInfo.
+        (WebCore::RenderBlock::finishDelayUpdateScrollInfo):
+            - Remove blocks from gDelayedUpdateScrollInfoSet one at a time, waiting for each block until it is
+              about to be updated.
+
 2012-12-13  Alexey Proskuryakov  <a...@apple.com>
 
         ResourceLoader::didReceiveAuthenticationChallenge uses a wrong client

Modified: trunk/Source/WebCore/rendering/RenderBlock.cpp (137631 => 137632)


--- trunk/Source/WebCore/rendering/RenderBlock.cpp	2012-12-13 19:46:13 UTC (rev 137631)
+++ trunk/Source/WebCore/rendering/RenderBlock.cpp	2012-12-13 19:48:26 UTC (rev 137632)
@@ -1289,8 +1289,8 @@
 
 void RenderBlock::startDelayUpdateScrollInfo()
 {
-    if (gDelayUpdateScrollInfo == 0) {
-        ASSERT(!gDelayedUpdateScrollInfoSet);
+    if (!gDelayedUpdateScrollInfoSet) {
+        ASSERT(!gDelayUpdateScrollInfo);
         gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
     }
     ASSERT(gDelayedUpdateScrollInfoSet);
@@ -1304,15 +1304,22 @@
     if (gDelayUpdateScrollInfo == 0) {
         ASSERT(gDelayedUpdateScrollInfoSet);
 
-        OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
-        gDelayedUpdateScrollInfoSet = 0;
-
-        for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
-            RenderBlock* block = *it;
-            if (block->hasOverflowClip()) {
-                block->layer()->updateScrollInfoAfterLayout();
+        Vector<RenderBlock*> infoSet;
+        while (gDelayedUpdateScrollInfoSet && gDelayedUpdateScrollInfoSet->size()) {
+            copyToVector(*gDelayedUpdateScrollInfoSet, infoSet);
+            for (Vector<RenderBlock*>::iterator it = infoSet.begin(); it != infoSet.end(); ++it) {
+                RenderBlock* block = *it;
+                // |block| may have been destroyed at this point, but then it will have been removed from gDelayedUpdateScrollInfoSet.
+                if (gDelayedUpdateScrollInfoSet && gDelayedUpdateScrollInfoSet->contains(block)) {
+                    gDelayedUpdateScrollInfoSet->remove(block);
+                    if (block->hasOverflowClip())
+                        block->layer()->updateScrollInfoAfterLayout();
+                }
             }
         }
+        delete gDelayedUpdateScrollInfoSet;
+        gDelayedUpdateScrollInfoSet = 0;
+        ASSERT(!gDelayUpdateScrollInfo);
     }
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to