Closed Bug 578977 Opened 9 years ago Closed 8 years ago

Crash [@ IsPercentageAware] with first-letter, position:fixed, etc

Categories

(Core :: Layout, defect, critical)

defect
Not set
critical

Tracking

()

RESOLVED FIXED
mozilla8
Tracking Status
blocking2.0 --- -
status2.0 --- wanted

People

(Reporter: martijn.martijn, Assigned: mats)

References

Details

(Keywords: crash, testcase)

Crash Data

Attachments

(5 files, 4 obsolete files)

Attached file testcase
See testcase, which crashes current trunk build, after you've resized the browser window.

http://crash-stats.mozilla.com/report/index/815b27c2-2d1a-477b-86bf-805662100715
0  	xul.dll  	IsPercentageAware  	 layout/generic/nsLineLayout.cpp:671
1 	mozcrt19.dll 	arena_malloc_small 	obj-firefox/memory/jemalloc/crtsrc/jemalloc.c:3734
2 	mozcrt19.dll 	malloc 	obj-firefox/memory/jemalloc/crtsrc/jemalloc.c:5811
3 	xul.dll 	nsTArray_base::EnsureCapacity 	obj-firefox/xpcom/build/nsTArray.cpp:76
4 	xul.dll 	xul.dll@0xbcb30f 	
5 	xul.dll 	nsContinuingTextFrame::Init 	
6 	xul.dll 	xul.dll@0x86e8f 	
7 	xul.dll 	PL_DHashTableOperate 	obj-firefox/xpcom/build/pldhash.c:625
8 	xul.dll 	mozilla::FramePropertyTable::Remove 	layout/base/FramePropertyTable.cpp:148
9 	xul.dll 	mozilla::FrameProperties::Remove 	obj-firefox/dist/include/FramePropertyTable.h:230
10 	xul.dll 	nsContainerFrame::StealOverflowFrames 	layout/generic/nsContainerFrame.h:623
11 	xul.dll 	nsLineLayout::BeginSpan 	layout/generic/nsLineLayout.cpp:435
12 	xul.dll 	nsFirstLetterFrame::Reflow 	layout/generic/nsFirstLetterFrame.cpp:234
blocking2.0: --- → ?
Oh, this is exciting.  The immediate cause of the crash is that we pass a null frame pointer to IsPercentageAware.  And that happens because the nsFirstLetterFrame has no textframe kid but nsFirstLetterFrame::Reflow assumes |kid| is non-null.

Looking at the frame tree, it looks like we have a block frame for the <td> which has a Letter frame containing the first 'm' on the first line.  That Letter frame has a continuation (containing " m"), and that has another continuation (containing " m").  This last also has an overflow list containing the single textframe with "m\u0639" in it, and a next-continuation which is a Letter frame with no kid which has _another_ next-continuation which is a Letter frame with no kid.

We're reflowing this last letter frame.

So it looks like we somehow failed to reflow the Letter frame that should have pulled stuff off the overflow list and destroyed that last empty continuation, right?
blocking2.0: ? → -
status2.0: --- → wanted
There were 122 reported crash incidents for IsPercentageAware in the past
two week period.  I think we should wallpaper (with an assert) the case
where kid == NULL until we think we have fixed this.
bp-1eef6369-ac50-496a-97c4-278962110126
Attached patch wallpaperSplinter Review
I don't think this is needed though, because I have found the real bug....
Assignee: nobody → matspal
Attached patch fix v1 (obsolete) — Splinter Review
After reflowing a first-letter child frame we have
NS_FRAME_IS_COMPLETE(aReflowStatus) and thus we delete all the kid's
next-in-flows.
http://hg.mozilla.org/mozilla-central/annotate/e98b94aa64fa/layout/generic/nsFirstLetterFrame.cpp#l257
This makes a bunch of |this| next-in-flows empty and nsLineLayout::ReflowFrame
only deletes the next-in-flows in the !NS_INLINE_IS_BREAK_BEFORE case
http://hg.mozilla.org/mozilla-central/annotate/e98b94aa64fa/layout/generic/nsLineLayout.cpp#l977
the else-clause just pushes the frame and leaves the empty first-letter
next-in-flows intact.
http://hg.mozilla.org/mozilla-central/annotate/e98b94aa64fa/layout/generic/nsLineLayout.cpp#l1063

Let me know if you want the wallpaper as well.  I don't think it should
be necessary.
Attachment #507764 - Flags: review?(roc)
Isn't the nsLineLayout code a bogus optimization? I think it should always delete the next-in-flows of the child even if NS_INLINE_IS_BREAK_BEFORE.
Attached patch fix v2 (obsolete) — Splinter Review
The crashtest triggers a couple of:
###!!! ASSERTION: Computed overflow area must contain frame bounds: 'aNewSize.width == 0 || aNewSize.height == 0 || aOverflowAreas.Overflow(otype).Contains(nsRect(nsPoint(0,0), aNewSize))', file layout/generic/nsFrame.cpp, line 6144

I'll file that separately.  (TryServer results pending...)

I collected some statistics (loading Alexa top 500 sites).
~7% of nsLineLayout::ReflowFrame calls ends up in the else-block,
of those ~1.7% has a next-in-flow.  In other words, only 0.01% of
nsLineLayout::ReflowFrame calls are affected by the "optimization".

Fwiw, I did a quick hack marking frames where we delete next-in-flows
(in the else-block) and then counting them in
nsCSSFrameConstructor::CreateContinuingFrame.
About 96% did call CreateContinuingFrame.
Attachment #507764 - Attachment is obsolete: true
Attachment #510662 - Flags: review?(roc)
Attachment #507764 - Flags: review?(roc)
Attached patch fix v2 (obsolete) — Splinter Review
Load the right test file...
Attachment #510662 - Attachment is obsolete: true
Attachment #510663 - Flags: review?(roc)
Attachment #510662 - Flags: review?(roc)
+      parent->DeleteNextInFlowChild(mPresContext, kidNextInFlow,
+                                    !NS_INLINE_IS_BREAK_BEFORE(aReflowStatus));

Shouldn't we just be passing "true" for aDeletingEmptyFrames?
If I pass PR_TRUE then nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows says
###!!! ASSERTION: frame tree not empty, but caller reported complete status: 'start == end || IsInLetterFrame(aSubtreeRoot)', file layout/base/nsLayoutUtils.cpp, line 3964
when loading layout/generic/crashtests/586806-1.html
This is a reduced testcase based on layout/generic/crashtests/586806-1.htm
Crash Signature: [@ IsPercentageAware]
Blocks: 672080
Attachment #510663 - Attachment is obsolete: true
Attachment #510663 - Flags: review?(roc)
Attached file frame dump #2
Here's a little more detail on what happens leading up the assertion
in nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows.

Where reflowing an inline, 0x7fffd7c353e0 (lime).  It calls
ReflowInlineFrame on its text frame child 0x7fffd7c35450 (yellow)
and the resulting status is INLINE_IS_BREAK_BEFORE, here:
http://mxr.mozilla.org/mozilla-central/source/layout/generic/nsInlineFrame.cpp#564
so we break out of the loop and don't reflow any more child frames.
Returning to nsLineLayout::ReflowFrame we now have a reflow status
this is INLINE_IS_BREAK_BEFORE and FRAME_IS_COMPLETE.

The previous patch removed the next-in-flow (blue) for the inline (lime)
which caused the assertion, since text frame (red) maps content.
I think removing the next-in-flow in this case is wrong -- when the
reflow status is INLINE_IS_BREAK_BEFORE whether it's also COMPLETE
or INCOMPLETE is irrelevant since we haven't even tried to reflow
all the child frames yet.

I think the real bug is in nsFirstLetterFrame::Reflow (see comment 6)
which caused these first-letter frame continuations to be empty in the
first place.
Attachment #512155 - Attachment is obsolete: true
Attached patch fix v3 (wdiff)Splinter Review
Don't mess with next-in-flows when the status is INLINE_IS_BREAK_BEFORE.
Attachment #546634 - Flags: review?(roc)
Comment on attachment 546634 [details] [diff] [review]
fix v3 (wdiff)

Review of attachment 546634 [details] [diff] [review]:
-----------------------------------------------------------------
Attachment #546634 - Flags: review?(roc) → review+
http://hg.mozilla.org/integration/mozilla-inbound/rev/29b042248bc4
http://hg.mozilla.org/integration/mozilla-inbound/rev/101cf2df62d5
Flags: in-testsuite+
OS: Windows 7 → All
Hardware: x86 → All
Whiteboard: [inbound]
Target Milestone: --- → mozilla8
http://hg.mozilla.org/mozilla-central/rev/29b042248bc4
Status: NEW → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
Whiteboard: [inbound]
Depends on: 698335
You need to log in before you can comment on or make changes to this bug.