REGRESSION(r169105) Dangling renderer pointer in SelectionSubtreeRoot::SelectionSubtr...
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Jun 2015 19:35:19 +0000 (19:35 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Jun 2015 19:35:19 +0000 (19:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=146116
rdar://problem/20959369

Reviewed by Brent Fulgham.

This patch ensures that we don't adjust the selection unless the visual selection still matches this subtree root.

When multiple selection roots are present we need to ensure that a RenderObject
only shows up in one of them.
RenderView::splitSelectionBetweenSubtrees(), as the name implies, splits the
selection and sets the selection range (start/end) on each selection root.
However, SelectionSubtreeRoot::adjustForVisibleSelection() later recomputes the range
based on visible selection and that could end up collecting renderers as selection start/end
from another selection subtree.
RenderObject's holds the last selection state (RenderObject::setSelectionState).
If we set a renderer first as "on selection border" and later "inside" using multiple selection roots,
we can't clean up selections properly when this object gets destroyed.
One of the roots ends up with a dangling RenderObject pointer.

Source/WebCore:

Test: fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees.html

* rendering/SelectionSubtreeRoot.cpp:
(WebCore::SelectionSubtreeRoot::adjustForVisibleSelection):

LayoutTests:

* fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees-expected.txt: Added.
* fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@185838 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees-expected.txt [new file with mode: 0644]
LayoutTests/fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/SelectionSubtreeRoot.cpp

index 760d4b6..f279f00 100644 (file)
@@ -1,3 +1,28 @@
+2015-06-22  Zalan Bujtas  <zalan@apple.com>
+
+        REGRESSION(r169105) Dangling renderer pointer in SelectionSubtreeRoot::SelectionSubtreeData.
+        https://bugs.webkit.org/show_bug.cgi?id=146116
+        rdar://problem/20959369
+
+        Reviewed by Brent Fulgham.
+
+        This patch ensures that we don't adjust the selection unless the visual selection still matches this subtree root.
+
+        When multiple selection roots are present we need to ensure that a RenderObject
+        only shows up in one of them.
+        RenderView::splitSelectionBetweenSubtrees(), as the name implies, splits the
+        selection and sets the selection range (start/end) on each selection root.
+        However, SelectionSubtreeRoot::adjustForVisibleSelection() later recomputes the range
+        based on visible selection and that could end up collecting renderers as selection start/end
+        from another selection subtree.
+        RenderObject's holds the last selection state (RenderObject::setSelectionState).
+        If we set a renderer first as "on selection border" and later "inside" using multiple selection roots,
+        we can't clean up selections properly when this object gets destroyed.
+        One of the roots ends up with a dangling RenderObject pointer.
+
+        * fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees-expected.txt: Added.
+        * fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees.html: Added.
+
 2015-06-22  Daniel Bates  <dabates@apple.com>
 
         AX: UI Automation cannot find AutoFill or search cancel buttons
diff --git a/LayoutTests/fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees-expected.txt b/LayoutTests/fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees-expected.txt
new file mode 100644 (file)
index 0000000..4ee3fc8
--- /dev/null
@@ -0,0 +1,4 @@
+foo
+Pass if no crash or assert in debug.
+foobar
+
diff --git a/LayoutTests/fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees.html b/LayoutTests/fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees.html
new file mode 100644 (file)
index 0000000..cf6c399
--- /dev/null
@@ -0,0 +1,19 @@
+<html id="webtest0">
+<head>
+<style>
+       :last-child { -webkit-flow-into: foo; }
+</style>
+
+<script>
+    if (window.testRunner)
+        testRunner.dumpAsText();
+    document.write("foo<br>");
+</script>
+</head>
+<body>Pass if no crash or assert in debug.<summary id="webtest5"><mathml><femerge></femerge></mathml>foobar<table></table></summary></body>
+<script>
+document.querySelector("#webtest0").appendChild(document.createElement("canvas"));
+document.execCommand("SelectAll");
+document.getElementById("webtest5").appendChild(document.createElement("feconvolvematrix"));
+</script>
+</html>
index e0fd6e8..ed700e1 100644 (file)
@@ -1,3 +1,30 @@
+2015-06-22  Zalan Bujtas  <zalan@apple.com>
+
+        REGRESSION(r169105) Dangling renderer pointer in SelectionSubtreeRoot::SelectionSubtreeData.
+        https://bugs.webkit.org/show_bug.cgi?id=146116
+        rdar://problem/20959369
+
+        Reviewed by Brent Fulgham.
+
+        This patch ensures that we don't adjust the selection unless the visual selection still matches this subtree root.
+
+        When multiple selection roots are present we need to ensure that a RenderObject
+        only shows up in one of them.
+        RenderView::splitSelectionBetweenSubtrees(), as the name implies, splits the
+        selection and sets the selection range (start/end) on each selection root.
+        However, SelectionSubtreeRoot::adjustForVisibleSelection() later recomputes the range
+        based on visible selection and that could end up collecting renderers as selection start/end
+        from another selection subtree.
+        RenderObject's holds the last selection state (RenderObject::setSelectionState).
+        If we set a renderer first as "on selection border" and later "inside" using multiple selection roots,
+        we can't clean up selections properly when this object gets destroyed.
+        One of the roots ends up with a dangling RenderObject pointer.
+
+        Test: fast/regions/crash-when-renderer-is-in-multiple-selection-subtrees.html
+
+        * rendering/SelectionSubtreeRoot.cpp:
+        (WebCore::SelectionSubtreeRoot::adjustForVisibleSelection):
+
 2015-06-22  Jeremy Jones  <jeremyj@apple.com>
 
         Do not exit fullscreen when starting PiP since this is done automatically.
index d207ea5..9f65e94 100644 (file)
@@ -70,15 +70,22 @@ void SelectionSubtreeRoot::adjustForVisibleSelection(Document& document)
 
     m_selectionSubtreeData.clearSelection();
 
-    if (startPos.isNotNull()
-        && endPos.isNotNull()
-        && selection.visibleStart() != selection.visibleEnd()
-        && startPos.deprecatedNode()->renderer()->flowThreadContainingBlock() == endPos.deprecatedNode()->renderer()->flowThreadContainingBlock()) {
-        m_selectionSubtreeData.setSelectionStart(startPos.deprecatedNode()->renderer());
-        m_selectionSubtreeData.setSelectionStartPos(startPos.deprecatedEditingOffset());
-        m_selectionSubtreeData.setSelectionEnd(endPos.deprecatedNode()->renderer());
-        m_selectionSubtreeData.setSelectionEndPos(endPos.deprecatedEditingOffset());
-    }
+    if (startPos.isNull() || endPos.isNull())
+        return;
+
+    if (selection.visibleStart() == selection.visibleEnd())
+        return;
+
+    if (startPos.deprecatedNode()->renderer()->flowThreadContainingBlock() != endPos.deprecatedNode()->renderer()->flowThreadContainingBlock())
+        return;
+
+    if (&startPos.deprecatedNode()->renderer()->selectionRoot() != this)
+        return;
+
+    m_selectionSubtreeData.setSelectionStart(startPos.deprecatedNode()->renderer());
+    m_selectionSubtreeData.setSelectionStartPos(startPos.deprecatedEditingOffset());
+    m_selectionSubtreeData.setSelectionEnd(endPos.deprecatedNode()->renderer());
+    m_selectionSubtreeData.setSelectionEndPos(endPos.deprecatedEditingOffset());
 }
 
 } // namespace WebCore