Bug 184748

Summary: SVG Text rendering causes infinite loop (spinning wait cursor)
Product: WebKit Reporter: samuel.hazlehurst
Component: SVGAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: mmaxfield, sabouhallawa, webkit-bug-importer, zimmermann
Priority: P2 Keywords: InRadar
Version: Safari 11   
Hardware: All   
OS: macOS 10.13   
See Also: https://bugs.webkit.org/show_bug.cgi?id=248357
Attachments:
Description Flags
File that demonstrates bug none

Description samuel.hazlehurst 2018-04-18 12:55:19 PDT
Created attachment 338247 [details]
File that demonstrates bug

Load attached svgError.html in Safari Version 11.1 (13605.1.33.1.2), enter a line in textarea (max 20 characters), press return, after typing first or second character, Safari will display wait cursor, CPU usage spikes, etc. /usr/bin/sample shows webkit stuck in WebCore::SVGTextLayoutEngine::currentLogicalCharacterMetrics (which suspiciously starts with the code 'while (true) {' :) 

Bug doesn't manifest 100% of the time, exhibits in both macOS & iOS safari, no other browsers I've tried.

/usr/bin/sample output: 

Sampling process 9893 for 3 seconds with 1 millisecond of run time between samples
Sampling completed, processing symbols...
Analysis of sampling com.apple.WebKit.WebContent (pid 9893) every 1 millisecond
Process:         com.apple.WebKit.WebContent [9893]
Path:            /System/Library/Frameworks/WebKit.framework/Versions/A/XPCServices/com.apple.WebKit.WebContent.xpc/Contents/MacOS/com.apple.WebKit.WebContent
Load Address:    0x10f3fa000
Identifier:      com.apple.WebKit.WebContent
Version:         13605 (13605.1.33.1.2)
Build Info:      WebKit2-7605001033001002~5
Code Type:       X86-64
Parent Process:  ??? [1]

Date/Time:       2018-04-18 15:28:10.240 -0400
Launch Time:     2018-04-18 15:24:58.835 -0400
OS Version:      Mac OS X 10.13.4 (17E199)
Report Version:  7
Analysis Tool:   /usr/bin/sample

Physical footprint:         25.1M
Physical footprint (peak):  61.1M
----

Call graph:
    2696 Thread_1465610   DispatchQueue_1: com.apple.main-thread  (serial)
    + 2696 start  (in libdyld.dylib) + 1  [0x7fff7b43f015]
    +   2696 ???  (in com.apple.WebKit.WebContent)  load address 0x10f3fa000 + 0x16a1  [0x10f3fb6a1]
    +     2696 xpc_main  (in libxpc.dylib) + 417  [0x7fff7b798baa]
    +       2696 _xpc_objc_main  (in libxpc.dylib) + 580  [0x7fff7b799f57]
    +         2696 NSApplicationMain  (in AppKit) + 804  [0x7fff50684a72]
    +           2696 -[NSApplication run]  (in AppKit) + 764  [0x7fff506b5885]
    +             2696 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]  (in AppKit) + 3044  [0x7fff50e56e34]
    +               2696 _DPSNextEvent  (in AppKit) + 2085  [0x7fff506c0a73]
    +                 2696 _BlockUntilNextEventMatchingListInModeWithFilter  (in HIToolbox) + 64  [0x7fff5240d884]
    +                   2696 ReceiveNextEventCommon  (in HIToolbox) + 613  [0x7fff5240db06]
    +                     2696 RunCurrentEventLoopInMode  (in HIToolbox) + 286  [0x7fff5240dd96]
    +                       2696 CFRunLoopRunSpecific  (in CoreFoundation) + 483  [0x7fff531251a3]
    +                         2696 __CFRunLoopRun  (in CoreFoundation) + 2427  [0x7fff53125dab]
    +                           2696 __CFRunLoopDoTimers  (in CoreFoundation) + 346  [0x7fff5312e7da]
    +                             2696 __CFRunLoopDoTimer  (in CoreFoundation) + 1095  [0x7fff5312ecd7]
    +                               2696 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__  (in CoreFoundation) + 20  [0x7fff5312f064]
    +                                 2696 WebCore::timerFired(__CFRunLoopTimer*, void*)  (in WebCore) + 31  [0x7fff6040846f]
    +                                   2696 WebCore::ThreadTimers::sharedTimerFiredInternal()  (in WebCore) + 176  [0x7fff60408530]
    +                                     2696 WebCore::LayoutContext::layout()  (in WebCore) + 1113  [0x7fff613ba2a9]
    +                                       2696 WebCore::RenderSVGRoot::layout()  (in WebCore) + 325  [0x7fff60516905]
    +                                         2696 WebCore::SVGRenderSupport::layoutChildren(WebCore::RenderElement&, bool)  (in WebCore) + 555  [0x7fff6175398b]
    +                                           2696 WebCore::RenderSVGText::layout()  (in WebCore) + 691  [0x7fff605d5723]
    +                                             2696 WebCore::RenderBlockFlow::layoutLineBoxes(bool, WebCore::LayoutUnit&, WebCore::LayoutUnit&)  (in WebCore) + 1729  [0x7fff615f32e1]
    +                                               2696 WebCore::RenderBlockFlow::layoutRunsAndFloats(WebCore::LineLayoutState&, bool)  (in WebCore) + 1253  [0x7fff615eee75]
    +                                                 2696 WebCore::RenderBlockFlow::layoutRunsAndFloatsInRange(WebCore::LineLayoutState&, WebCore::BidiResolverWithIsolate<WebCore::InlineIterator, WebCore::BidiRun, WebCore::BidiIsolatedRun>&, WebCore::InlineIterator const&, WebCore::BidiStatus const&, unsigned int)  (in WebCore) + 5604  [0x7fff615f1434]
    +                                                   2696 WebCore::RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned int, WebCore::BidiRunList<WebCore::BidiRun>&, WebCore::InlineIterator const&, WebCore::LineInfo&, WebCore::VerticalPositionCache&, WebCore::BidiRun*, WTF::Vector<WebCore::WordMeasurement, 64ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&)  (in WebCore) + 220  [0x7fff615ee8ac]
    +                                                     2696 WebCore::SVGRootInlineBox::computePerCharacterLayoutInformation()  (in WebCore) + 464  [0x7fff605d6a00]
    +                                                       2696 WebCore::SVGRootInlineBox::layoutCharactersInTextBoxes(WebCore::InlineFlowBox*, WebCore::SVGTextLayoutEngine&)  (in WebCore) + 493  [0x7fff605d6c7d]
    +                                                         2696 WebCore::SVGRootInlineBox::layoutCharactersInTextBoxes(WebCore::InlineFlowBox*, WebCore::SVGTextLayoutEngine&)  (in WebCore) + 183  [0x7fff605d6b47]
    +                                                           2696 WebCore::SVGRootInlineBox::layoutCharactersInTextBoxes(WebCore::InlineFlowBox*, WebCore::SVGTextLayoutEngine&)  (in WebCore) + 104  [0x7fff605d6af8]
    +                                                             2696 WebCore::SVGTextLayoutEngine::layoutInlineTextBox(WebCore::SVGInlineTextBox&)  (in WebCore) + 122  [0x7fff6175cb4a]
    +                                                               2696 WebCore::SVGTextLayoutEngine::layoutTextOnLineOrPath(WebCore::SVGInlineTextBox&, WebCore::RenderSVGInlineText&, WebCore::RenderStyle const&)  (in WebCore) + 1054  [0x7fff6175eb3e]
    +                                                                 1835 WebCore::SVGTextLayoutEngine::currentLogicalCharacterMetrics(WebCore::SVGTextLayoutAttributes*&, WebCore::SVGTextMetrics&)  (in WebCore) + 324  [0x7fff605d70c4]
    +                                                                 ! 1835 WebCore::SVGTextLayoutEngine::currentLogicalCharacterAttributes(WebCore::SVGTextLayoutAttributes*&)  (in WebCore) + 117,16,...  [0x7fff605d6f75,0x7fff605d6f10,...]
    +                                                                 861 WebCore::SVGTextLayoutEngine::currentLogicalCharacterMetrics(WebCore::SVGTextLayoutAttributes*&, WebCore::SVGTextMetrics&)  (in WebCore) + 324,33,...  [0x7fff605d70c4,0x7fff605d6fa1,...]
Comment 1 Radar WebKit Bug Importer 2018-04-20 23:42:39 PDT
<rdar://problem/39618637>
Comment 2 Said Abou-Hallawa 2018-04-24 18:03:27 PDT
The hang happens because of a collapsing text run. A collapsing text run is a run which has logical attributes, i.e. text, but does not logical metrics, i.e. with and height.

The real problem is SVGTextLayoutEngine::currentLogicalCharacterAttributes() and SVGTextLayoutEngine::currentLogicalCharacterMetrics() do not advance m_layoutAttributesPosition based on the same condition.

-- SVGTextLayoutEngine::currentLogicalCharacterAttributes() advances m_layoutAttributesPosition only if (m_logicalCharacterOffset == logicalAttributes->context().text().length())

-- SVGTextLayoutEngine::currentLogicalCharacterMetrics() expects m_layoutAttributesPosition to be advanced if (m_logicalMetricsListOffset == textMetricsSize)

And these conditions will not match if the layoutAttribute is for a collapsed run.