⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 283311 in webkit


Ignore:
Timestamp:
Sep 30, 2021, 7:53:33 AM (5 years ago)
Author:
Antti Koivisto
Message:

Source/WebCore:
Regression (283158): Having unused TextIterator instance shouldn't crash if document is mutated
https://bugs.webkit.org/show_bug.cgi?id=231013
rdar://83690985

Reviewed by Alan Bujtas.

By using bundle APIs it is possible to create a retained TextIterator and hit CheckedPtr assertion because layout
is torn down while iterator still exists. This is not dangerous in itself so can be supported.

This patch ensures LineLayout disconnects cleanly from (refcounted) InlineContent.

Test: editing/text-iterator/text-iterator-document-mutation.html

  • layout/integration/LayoutIntegrationInlineContent.cpp:

(WebCore::LayoutIntegration::InlineContent::clearAndDetach):

Remove all content and clear the LineLayout pointer.

This is safe since iterators refer to content via indexes and any attempt to access
via them will hit nullptrs or vector asserts.

  • layout/integration/LayoutIntegrationInlineContent.h:

(WebCore::LayoutIntegration::InlineContent::lineLayout const):

  • layout/integration/LayoutIntegrationLineLayout.cpp:

(WebCore::LayoutIntegration::LineLayout::~LineLayout):
(WebCore::LayoutIntegration::LineLayout::layout):
(WebCore::LayoutIntegration::LineLayout::hitTest):
(WebCore::LayoutIntegration::LineLayout::clearInlineContent):

Clear InlineContent before nulling it as it can still be kept alive by iterators.

  • layout/integration/LayoutIntegrationLineLayout.h:
  • testing/Internals.cpp:

(WebCore::Internals::retainTextIteratorForDocumentContent):

  • testing/Internals.h:
  • testing/Internals.idl:

LayoutTests:
Having unused TextIterator instance shouldn't crash if document is mutated
https://bugs.webkit.org/show_bug.cgi?id=231013
rdar://83690985

Reviewed by Alan Bujtas.

  • editing/text-iterator/text-iterator-document-mutation-expected.txt: Added.
  • editing/text-iterator/text-iterator-document-mutation.html: Added.
Location:
trunk
Files:
2 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r283310 r283311  
     12021-09-30  Antti Koivisto  <antti@apple.com>
     2
     3        Having unused TextIterator instance shouldn't crash if document is mutated
     4        https://bugs.webkit.org/show_bug.cgi?id=231013
     5        rdar://83690985
     6
     7        Reviewed by Alan Bujtas.
     8
     9        * editing/text-iterator/text-iterator-document-mutation-expected.txt: Added.
     10        * editing/text-iterator/text-iterator-document-mutation.html: Added.
     11
    1122021-09-30  Lauro Moura  <lmoura@igalia.com>
    213
  • trunk/Source/WebCore/ChangeLog

    r283309 r283311  
     12021-09-30  Antti Koivisto  <antti@apple.com>
     2
     3        Regression (283158): Having unused TextIterator instance shouldn't crash if document is mutated
     4        https://bugs.webkit.org/show_bug.cgi?id=231013
     5        rdar://83690985
     6
     7        Reviewed by Alan Bujtas.
     8
     9        By using bundle APIs it is possible to create a retained TextIterator and hit CheckedPtr assertion because layout
     10        is torn down while iterator still exists. This is not dangerous in itself so can be supported.
     11
     12        This patch ensures LineLayout disconnects cleanly from (refcounted) InlineContent.
     13
     14        Test: editing/text-iterator/text-iterator-document-mutation.html
     15
     16        * layout/integration/LayoutIntegrationInlineContent.cpp:
     17        (WebCore::LayoutIntegration::InlineContent::clearAndDetach):
     18
     19        Remove all content and clear the LineLayout pointer.
     20
     21        This is safe since iterators refer to content via indexes and any attempt to access
     22        via them will hit nullptrs or vector asserts.
     23
     24        * layout/integration/LayoutIntegrationInlineContent.h:
     25        (WebCore::LayoutIntegration::InlineContent::lineLayout const):
     26        * layout/integration/LayoutIntegrationLineLayout.cpp:
     27        (WebCore::LayoutIntegration::LineLayout::~LineLayout):
     28        (WebCore::LayoutIntegration::LineLayout::layout):
     29        (WebCore::LayoutIntegration::LineLayout::hitTest):
     30        (WebCore::LayoutIntegration::LineLayout::clearInlineContent):
     31
     32        Clear InlineContent before nulling it as it can still be kept alive by iterators.
     33
     34        * layout/integration/LayoutIntegrationLineLayout.h:
     35        * testing/Internals.cpp:
     36        (WebCore::Internals::retainTextIteratorForDocumentContent):
     37        * testing/Internals.h:
     38        * testing/Internals.idl:
     39
    1402021-09-30  Enrique Ocaña González  <eocanha@igalia.com>
    241
  • trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContent.cpp

    r283158 r283311  
    144144}
    145145
     146void InlineContent::clearAndDetach()
     147{
     148    releaseCaches();
     149    boxes.clear();
     150    lines.clear();
     151    m_lineLayout = nullptr;
     152}
     153
    146154void InlineContent::releaseCaches()
    147155{
  • trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContent.h

    r283158 r283311  
    6969    void shrinkToFit();
    7070
    71     const LineLayout& lineLayout() const { return m_lineLayout; }
     71    const LineLayout& lineLayout() const { return *m_lineLayout; }
    7272    const RenderObject& rendererForLayoutBox(const Layout::Box&) const;
    7373    const RenderBlockFlow& containingBlock() const;
     
    8181    const Vector<size_t>& nonRootInlineBoxIndexesForLayoutBox(const Layout::Box&) const;
    8282
     83    void clearAndDetach();
    8384    void releaseCaches();
    8485
     
    8687    InlineContent(const LineLayout&);
    8788
    88     CheckedRef<const LineLayout> m_lineLayout;
     89    CheckedPtr<const LineLayout> m_lineLayout;
    8990
    9091    using FirstBoxIndexCache = HashMap<CheckedRef<const Layout::Box>, size_t>;
  • trunk/Source/WebCore/layout/integration/LayoutIntegrationLineLayout.cpp

    r283158 r283311  
    6868}
    6969
    70 LineLayout::~LineLayout() = default;
     70LineLayout::~LineLayout()
     71{
     72    clearInlineContent();
     73}
    7174
    7275RenderBlockFlow* LineLayout::blockContainer(RenderObject& renderer)
     
    219222
    220223    // FIXME: Do not clear the lines and boxes here unconditionally, but consult with the damage object instead.
    221     m_inlineContent = nullptr;
     224    clearInlineContent();
     225
    222226    auto& rootGeometry = m_layoutState.geometryForBox(rootLayoutBox);
    223227    auto inlineFormattingContext = Layout::InlineFormattingContext { rootLayoutBox, m_inlineFormattingState, m_lineDamage.get() };
     
    573577}
    574578
     579void LineLayout::clearInlineContent()
     580{
     581    if (!m_inlineContent)
     582        return;
     583    m_inlineContent->clearAndDetach();
     584    m_inlineContent = nullptr;
     585}
     586
    575587void LineLayout::paintTextBoxUsingPhysicalCoordinates(PaintInfo& paintInfo, const LayoutPoint& paintOffset, const InlineDisplay::Box& textBox)
    576588{
  • trunk/Source/WebCore/layout/integration/LayoutIntegrationLineLayout.h

    r283158 r283311  
    130130    const Layout::ContainerBox& rootLayoutBox() const;
    131131    Layout::ContainerBox& rootLayoutBox();
     132    void clearInlineContent();
    132133    void releaseCaches();
    133134
  • trunk/Source/WebCore/testing/Internals.cpp

    r283033 r283311  
    65386538#endif
    65396539
     6540void Internals::retainTextIteratorForDocumentContent()
     6541{
     6542    auto* document = contextDocument();
     6543    if (!document)
     6544        return;
     6545
     6546    auto range = makeRangeSelectingNodeContents(*document);
     6547    m_textIterator = makeUnique<TextIterator>(range);
     6548}
     6549
     6550
    65406551} // namespace WebCore
  • trunk/Source/WebCore/testing/Internals.h

    r283033 r283311  
    103103class StringCallback;
    104104class StyleSheet;
     105class TextIterator;
    105106class TextTrack;
    106107class TimeRanges;
     
    11911192    ExceptionOr<void> setDocumentAutoplayPolicy(Document&, AutoplayPolicy);
    11921193
     1194    void retainTextIteratorForDocumentContent();
     1195
    11931196private:
    11941197    explicit Internals(Document&);
     
    12201223    HashMap<unsigned, std::unique_ptr<WebCore::SleepDisabler>> m_sleepDisablers;
    12211224
     1225    std::unique_ptr<TextIterator> m_textIterator;
     1226
    12221227#if ENABLE(WEBXR)
    12231228    RefPtr<WebXRTest> m_xrTest;
  • trunk/Source/WebCore/testing/Internals.idl

    r282686 r283311  
    10641064
    10651065    undefined setDocumentAutoplayPolicy(Document document, AutoplayPolicy policy);
    1066 };
     1066
     1067    undefined retainTextIteratorForDocumentContent();
     1068};
Note: See TracChangeset for help on using the changeset viewer.