RESOLVED FIXED162933
REGRESSION(r203289): Assertion in MathOperator::stretchTo() on Wikipedia Page
https://bugs.webkit.org/show_bug.cgi?id=162933
Summary REGRESSION(r203289): Assertion in MathOperator::stretchTo() on Wikipedia Page
Brent Fulgham
Reported 2016-10-04 13:29:06 PDT
Visit the Wikipedia page for Levenshtein Distance in a debug build of WebKit: https://en.wikipedia.org/wiki/Levenshtein_distance This triggers the following assertion: void MathOperator::stretchTo(const RenderStyle& style, LayoutUnit targetSize) { ASSERT(m_operatorType == Type::VerticalOperator || m_operatorType == Type::HorizontalOperator); calculateStretchyData(style, false, targetSize); if (m_stretchType == StretchType::GlyphAssembly) { The assertion fires because we are attempting to apply the 'stretchTo' operation on a "NormalOperator" type.
Attachments
Test Case showing the null image (1014 bytes, text/html)
2016-10-31 16:52 PDT, Brent Fulgham
no flags
Patch (885 bytes, patch)
2016-11-01 01:25 PDT, Frédéric Wang Nélar
no flags
Patch (8.59 KB, patch)
2016-11-01 13:01 PDT, Brent Fulgham
no flags
Patch (7.94 KB, patch)
2016-11-02 12:11 PDT, Brent Fulgham
dino: review+
Brent Fulgham
Comment 1 2016-10-04 13:30:16 PDT
Frédéric Wang Nélar
Comment 2 2016-10-04 23:43:06 PDT
Are you able to isolate the MathML fragment that triggers the assertion? As I see, RenderMathMLOperator::updateMathOperator() sets the type to NormalOperator if !shouldAllowStretching() i.e. we don't have !(textContent() && (hasOperatorFlag(MathMLOperatorDictionary::Stretchy) || isLargeOperatorInDisplayStyle())) On the other hand, MathOperator::stretchTo are called from the RenderMathMLOperator::stretchTo functions that explicitly checks hasOperatorFlag(MathMLOperatorDictionary::Stretchy). Is is possible that textContent() is empty? Or that RenderMathMLOperator::updateMathOperator() has not been called in time?
Brent Fulgham
Comment 3 2016-10-31 13:57:41 PDT
(In reply to comment #2) > Are you able to isolate the MathML fragment that triggers the assertion? I don't have a reduced test case. > ... Is is possible that > textContent() is empty? Or that RenderMathMLOperator::updateMathOperator() > has not been called in time? 'textContent' is not empty. The 'operatorChar' member is set to "{".
Brent Fulgham
Comment 4 2016-10-31 14:00:49 PDT
(In reply to comment #3) Wait! I take it all back. I was not hitting the crash when I inspected those values. It appears that the RenderMathMLOperator object has an operatorChar of "", so yes -- it does seem to be empty.
Frédéric Wang Nélar
Comment 5 2016-10-31 14:08:47 PDT
(In reply to comment #4) > (In reply to comment #3) > > Wait! I take it all back. I was not hitting the crash when I inspected those > values. > > It appears that the RenderMathMLOperator object has an operatorChar of "", > so yes -- it does seem to be empty. OK, in that case we only need to avoid the (two IIRC?) calls to RenderMathMLOperator::stretchTo when the textContent == 0 (and maybe add assert in RenderMathMLOperator::stretchTo too).
Brent Fulgham
Comment 6 2016-10-31 16:52:20 PDT
Created attachment 293495 [details] Test Case showing the null image Reduced test case.
Brent Fulgham
Comment 7 2016-10-31 16:53:16 PDT
The assertion gets hit with the attached test case, specifically with this line: <mo fence="true" stretchy="true"></mo> Looks like we need to account for the possibility that content may be generated with an empty element of this kind.
Frédéric Wang Nélar
Comment 8 2016-11-01 01:05:01 PDT
(In reply to comment #7) > The assertion gets hit with the attached test case, specifically with this > line: > > <mo fence="true" stretchy="true"></mo> > > Looks like we need to account for the possibility that content may be > generated with an empty element of this kind. Yes, I think it will be considered vertical + stretchy. fence="true" should not be needed to trigger the assert.
Frédéric Wang Nélar
Comment 9 2016-11-01 01:25:41 PDT
Created attachment 293537 [details] Patch @Brent: This is a quick untested patch. Maybe a stronger solution is just to introduce bool RenderMathMLOperator::isStretchy() { return textContent() && element().hasProperty(MathMLOperatorDictionary::Stretchy); } and then replace each call to RenderMathMLOperator::hasProperty(MathMLOperatorDictionary::Stretchy) in the RenderMathML* classes with a call to RenderMathMLOperator::isStretchy().
Brent Fulgham
Comment 10 2016-11-01 10:51:31 PDT
(In reply to comment #9) > Created attachment 293537 [details] > Patch > > @Brent: This is a quick untested patch. Maybe a stronger solution is just to > introduce > > bool RenderMathMLOperator::isStretchy() > { > return textContent() && > element().hasProperty(MathMLOperatorDictionary::Stretchy); > } > > and then replace each call to > RenderMathMLOperator::hasProperty(MathMLOperatorDictionary::Stretchy) in the > RenderMathML* classes with a call to RenderMathMLOperator::isStretchy(). Could we just use "shouldAllowStretching()"? It is very similar: bool RenderMathMLOperator::shouldAllowStretching() const { return textContent() && (hasOperatorFlag(MathMLOperatorDictionary::Stretchy) || isLargeOperatorInDisplayStyle()); }
Brent Fulgham
Comment 11 2016-11-01 12:30:07 PDT
I confirmed that Frédéric's patch works. We can generate a final patch once he confirms whether the existing shouldAllowStretching is suitable, or if we must use the new 'isStretchy()' method.
Frédéric Wang Nélar
Comment 12 2016-11-01 12:35:48 PDT
(In reply to comment #10) > Could we just use "shouldAllowStretching()"? It is very similar: > > bool RenderMathMLOperator::shouldAllowStretching() const > { > return textContent() && > (hasOperatorFlag(MathMLOperatorDictionary::Stretchy) || > isLargeOperatorInDisplayStyle()); > } I don't think so, stretchTo must only be called with stretchy operators. If we include large operators in displaystyle (e.g. <math display="block"><mo>&Sum</mo></math>) then I suspect you can also hit an ASSERT in RenderMathMLOperator because hasOperatorFlag(MathMLOperatorDictionary::Stretchy) is not satisfied.
Frédéric Wang Nélar
Comment 13 2016-11-01 12:51:14 PDT
(In reply to comment #10) > Could we just use "shouldAllowStretching()"? Incidentally, I suspect this method is just a legacy of old code that was kept after the refactoring. I believe that now we can just expand it inside RenderMathMLOperator::updateMathOperator() by doing something like: if (isStretchy()) type = isVertical() ? MathOperator::Type::VerticalOperator : MathOperator::Type::HorizontalOperator; else if (textContent() && isLargeOperatorInDisplayStyle()) type = MathOperator::Type::DisplayOperator; else type = MathOperator::Type::NormalOperator; and then the condition in RenderMathMLOperator::useMathOperator() will just become m_mathOperator.type() != MathOperator::Type::NormalOperator || textContent() == minusSign where we add the accessor MathOperator::type() { return m_operatorType; } We can even include the textContent() check inside isLargeOperatorInDisplayStyle and discard the case <math display="block"><mo largeop="true"></mo></math>.
Brent Fulgham
Comment 14 2016-11-01 13:01:54 PDT
Brent Fulgham
Comment 15 2016-11-01 13:06:08 PDT
(In reply to comment #13) > (In reply to comment #10) > > Could we just use "shouldAllowStretching()"? > > Incidentally, I suspect this method is just a legacy of old code that was > kept after the refactoring. I believe that now we can just expand it inside > RenderMathMLOperator::updateMathOperator() by doing something like: > > if (isStretchy()) > type = isVertical() ? MathOperator::Type::VerticalOperator : > MathOperator::Type::HorizontalOperator; > else if (textContent() && isLargeOperatorInDisplayStyle()) > type = MathOperator::Type::DisplayOperator; > else > type = MathOperator::Type::NormalOperator; > > and then the condition in RenderMathMLOperator::useMathOperator() will just > become > > m_mathOperator.type() != MathOperator::Type::NormalOperator || textContent() > == minusSign > > where we add the accessor MathOperator::type() { return m_operatorType; } > > We can even include the textContent() check inside > isLargeOperatorInDisplayStyle and discard the case <math display="block"><mo > largeop="true"></mo></math>. Seems like a nice idea for a future refactoring! :-)
Frédéric Wang Nélar
Comment 16 2016-11-02 02:19:53 PDT
Comment on attachment 293573 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=293573&action=review lgtm, but I'm not a reviewer. > Source/WebCore/ChangeLog:11 > + We shouldn't be trying to apply stretch operations on an empty MathML element. Create a I think it's actually any operator that is not made of a single character. For example the assert probably happens with <mo stretchy="true">++<mo> too. > LayoutTests/mathml/empty-mo.html:8 > + <math xmlns="http://www.w3.org/1998/Math/MathML"> Maybe you can reduce this test case to <math><mo stretchy="true"></mo></math> ?
Frédéric Wang Nélar
Comment 17 2016-11-02 02:24:43 PDT
(In reply to comment #15) > Seems like a nice idea for a future refactoring! :-) I opened bug 164313
Alejandro G. Castro
Comment 18 2016-11-02 05:16:32 PDT
(In reply to comment #16) > Comment on attachment 293573 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=293573&action=review > > lgtm, but I'm not a reviewer. > lgtm too. > > Source/WebCore/ChangeLog:11 > > + We shouldn't be trying to apply stretch operations on an empty MathML element. Create a > > I think it's actually any operator that is not made of a single character. > For example the assert probably happens with <mo stretchy="true">++<mo> too. > Can we add also this case (++) to the test, and check if the textContent() part of the condition is doing what we want for that case.
Brent Fulgham
Comment 19 2016-11-02 12:11:16 PDT
Comment on attachment 293573 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=293573&action=review >>> Source/WebCore/ChangeLog:11 >>> + We shouldn't be trying to apply stretch operations on an empty MathML element. Create a >> >> I think it's actually any operator that is not made of a single character. For example the assert probably happens with <mo stretchy="true">++<mo> too. > > Can we add also this case (++) to the test, and check if the textContent() part of the condition is doing what we want for that case. Done.
Brent Fulgham
Comment 20 2016-11-02 12:11:23 PDT
Brent Fulgham
Comment 21 2016-11-02 12:12:26 PDT
(In reply to comment #16) > Comment on attachment 293573 [details] > Maybe you can reduce this test case to <math><mo > stretchy="true"></mo></math> ? Yes, this did work. I've revised the test cases as you suggested.
Brent Fulgham
Comment 22 2016-11-02 12:50:13 PDT
Note You need to log in before you can comment on or make changes to this bug.