Closed Bug 1582019 Opened 5 years ago Closed 5 years ago

Assertion failure: [GFX1]: invalid offset 13 for gfxSkipChars length 6, at /builds/worker/workspace/build/src/gfx/2d/Logging.h:740

Categories

(Core :: Layout: Columns, defect, P3)

defect

Tracking

()

VERIFIED FIXED
mozilla71
Tracking Status
firefox-esr60 --- unaffected
firefox-esr68 --- disabled
firefox67 --- disabled
firefox68 --- disabled
firefox69 --- disabled
firefox70 --- disabled
firefox71 --- verified
firefox72 --- verified
firefox73 --- verified

People

(Reporter: tsmith, Assigned: TYLin)

References

(Blocks 1 open bug)

Details

(4 keywords, Whiteboard: [post-critsmash-triage])

Attachments

(3 files, 1 obsolete file)

Attached file testcase.html (obsolete) —

Invalid offset sounds like it could be s-s.

Assertion failure: [GFX1]: invalid offset 13 for gfxSkipChars length 6, at /builds/worker/workspace/build/src/gfx/2d/Logging.h:740

#0 mozilla::gfx::Log<1, mozilla::gfx::CriticalLogger>::WriteLog(std::string const&) src/gfx/2d/Logging.h:741:9
#1 mozilla::gfx::Log<1, mozilla::gfx::CriticalLogger>::Flush() src/gfx/2d/Logging.h:279:7
#2 mozilla::gfx::Log<1, mozilla::gfx::CriticalLogger>::~Log() src/gfx/2d/Logging.h:272:12
#3 gfxSkipCharsIterator::SetOriginalOffset(int) src/gfx/thebes/gfxSkipChars.cpp:22:5
#4 gfxSkipCharsIterator::ConvertOriginalToSkipped(int) src/obj-firefox/dist/include/gfxSkipChars.h:192:5
#5 nsTextFrame::ReflowText(nsLineLayout&, int, mozilla::gfx::DrawTarget*, mozilla::ReflowOutput&, nsReflowStatus&) src/layout/generic/nsTextFrame.cpp:9174:3
#6 nsLineLayout::ReflowFrame(nsIFrame*, nsReflowStatus&, mozilla::ReflowOutput*, bool&) src/layout/generic/nsLineLayout.cpp:880:40
#7 nsInlineFrame::ReflowInlineFrame(nsPresContext*, mozilla::ReflowInput const&, nsInlineFrame::InlineReflowInput&, nsIFrame*, nsReflowStatus&) src/layout/generic/nsInlineFrame.cpp:674:15
#8 nsInlineFrame::ReflowFrames(nsPresContext*, mozilla::ReflowInput const&, nsInlineFrame::InlineReflowInput&, mozilla::ReflowOutput&, nsReflowStatus&) src/layout/generic/nsInlineFrame.cpp:548:7
#9 nsInlineFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsInlineFrame.cpp:363:3
#10 nsLineLayout::ReflowFrame(nsIFrame*, nsReflowStatus&, mozilla::ReflowOutput*, bool&) src/layout/generic/nsLineLayout.cpp:877:13
#11 nsInlineFrame::ReflowInlineFrame(nsPresContext*, mozilla::ReflowInput const&, nsInlineFrame::InlineReflowInput&, nsIFrame*, nsReflowStatus&) src/layout/generic/nsInlineFrame.cpp:674:15
#12 nsInlineFrame::ReflowFrames(nsPresContext*, mozilla::ReflowInput const&, nsInlineFrame::InlineReflowInput&, mozilla::ReflowOutput&, nsReflowStatus&) src/layout/generic/nsInlineFrame.cpp:548:7
#13 nsInlineFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsInlineFrame.cpp:363:3
#14 nsLineLayout::ReflowFrame(nsIFrame*, nsReflowStatus&, mozilla::ReflowOutput*, bool&) src/layout/generic/nsLineLayout.cpp:877:13
#15 nsBlockFrame::ReflowInlineFrame(mozilla::BlockReflowInput&, nsLineLayout&, nsLineList_iterator, nsIFrame*, LineReflowStatus*) src/layout/generic/nsBlockFrame.cpp:4331:15
#16 nsBlockFrame::DoReflowInlineFrames(mozilla::BlockReflowInput&, nsLineLayout&, nsLineList_iterator, nsFlowAreaRect&, int&, nsFloatManager::SavedState*, bool*, LineReflowStatus*, bool) src/layout/generic/nsBlockFrame.cpp:4133:5
#17 nsBlockFrame::ReflowInlineFrames(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) src/layout/generic/nsBlockFrame.cpp:4018:9
#18 nsBlockFrame::ReflowLine(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) src/layout/generic/nsBlockFrame.cpp:2997:5
#19 nsBlockFrame::ReflowDirtyLines(mozilla::BlockReflowInput&) src/layout/generic/nsBlockFrame.cpp:2823:11
#20 nsBlockFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsBlockFrame.cpp:1280:3
#21 nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, mozilla::WritingMode const&, mozilla::LogicalPoint const&, nsSize const&, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) src/layout/generic/nsContainerFrame.cpp:910:14
#22 nsColumnSetFrame::ReflowChildren(mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&, nsColumnSetFrame::ReflowConfig const&, bool) src/layout/generic/nsColumnSetFrame.cpp:781:7
#23 nsColumnSetFrame::ReflowColumns(mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&, nsColumnSetFrame::ReflowConfig&, bool) src/layout/generic/nsColumnSetFrame.cpp:454:37
#24 nsColumnSetFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsColumnSetFrame.cpp:1286:37
#25 nsBlockReflowContext::ReflowBlock(mozilla::LogicalRect const&, bool, nsCollapsingMargin&, int, bool, nsLineBox*, mozilla::ReflowInput&, nsReflowStatus&, mozilla::BlockReflowInput&) src/layout/generic/nsBlockReflowContext.cpp:291:11
#26 nsBlockFrame::ReflowBlockFrame(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) src/layout/generic/nsBlockFrame.cpp:3649:11
#27 nsBlockFrame::ReflowLine(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) src/layout/generic/nsBlockFrame.cpp:2994:5
#28 nsBlockFrame::ReflowDirtyLines(mozilla::BlockReflowInput&) src/layout/generic/nsBlockFrame.cpp:2823:11
#29 nsBlockFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsBlockFrame.cpp:1280:3
#30 nsBlockReflowContext::ReflowBlock(mozilla::LogicalRect const&, bool, nsCollapsingMargin&, int, bool, nsLineBox*, mozilla::ReflowInput&, nsReflowStatus&, mozilla::BlockReflowInput&) src/layout/generic/nsBlockReflowContext.cpp:291:11
#31 nsBlockFrame::ReflowBlockFrame(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) src/layout/generic/nsBlockFrame.cpp:3649:11
#32 nsBlockFrame::ReflowLine(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) src/layout/generic/nsBlockFrame.cpp:2994:5
#33 nsBlockFrame::ReflowDirtyLines(mozilla::BlockReflowInput&) src/layout/generic/nsBlockFrame.cpp:2537:7
#34 nsBlockFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsBlockFrame.cpp:1280:3
#35 nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, mozilla::WritingMode const&, mozilla::LogicalPoint const&, nsSize const&, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) src/layout/generic/nsContainerFrame.cpp:910:14
#36 nsColumnSetFrame::ReflowChildren(mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&, nsColumnSetFrame::ReflowConfig const&, bool) src/layout/generic/nsColumnSetFrame.cpp:781:7
#37 nsColumnSetFrame::ReflowColumns(mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&, nsColumnSetFrame::ReflowConfig&, bool) src/layout/generic/nsColumnSetFrame.cpp:454:37
#38 nsColumnSetFrame::FindBestBalanceBSize(mozilla::ReflowInput const&, nsPresContext*, nsColumnSetFrame::ReflowConfig&, nsColumnSetFrame::ColumnBalanceData, mozilla::ReflowOutput&, bool, nsReflowStatus&) src/layout/generic/nsColumnSetFrame.cpp:1219:7
#39 nsColumnSetFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsColumnSetFrame.cpp:1293:5
#40 nsBlockReflowContext::ReflowBlock(mozilla::LogicalRect const&, bool, nsCollapsingMargin&, int, bool, nsLineBox*, mozilla::ReflowInput&, nsReflowStatus&, mozilla::BlockReflowInput&) src/layout/generic/nsBlockReflowContext.cpp:291:11
#41 nsBlockFrame::ReflowBlockFrame(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) src/layout/generic/nsBlockFrame.cpp:3649:11
#42 nsBlockFrame::ReflowLine(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) src/layout/generic/nsBlockFrame.cpp:2994:5
#43 nsBlockFrame::ReflowDirtyLines(mozilla::BlockReflowInput&) src/layout/generic/nsBlockFrame.cpp:2537:7
#44 nsBlockFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsBlockFrame.cpp:1280:3
#45 nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, mozilla::WritingMode const&, mozilla::LogicalPoint const&, nsSize const&, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) src/layout/generic/nsContainerFrame.cpp:910:14
#46 nsCanvasFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsCanvasFrame.cpp:729:5
#47 nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, mozilla::WritingMode const&, mozilla::LogicalPoint const&, nsSize const&, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) src/layout/generic/nsContainerFrame.cpp:910:14
#48 nsHTMLScrollFrame::ReflowScrolledFrame(mozilla::ScrollReflowInput*, bool, bool, mozilla::ReflowOutput*) src/layout/generic/nsGfxScrollFrame.cpp:644:3
#49 nsHTMLScrollFrame::ReflowContents(mozilla::ScrollReflowInput*, mozilla::ReflowOutput const&) src/layout/generic/nsGfxScrollFrame.cpp:793:7
#50 nsHTMLScrollFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/nsGfxScrollFrame.cpp:1160:3
#51 nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, int, int, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) src/layout/generic/nsContainerFrame.cpp:950:14
#52 mozilla::ViewportFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) src/layout/generic/ViewportFrame.cpp:299:7
#53 mozilla::PresShell::DoReflow(nsIFrame*, bool, mozilla::OverflowChangedTracker*) src/layout/base/PresShell.cpp:9221:11
#54 mozilla::PresShell::ProcessReflowCommands(bool) src/layout/base/PresShell.cpp:9391:24
#55 mozilla::PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush) src/layout/base/PresShell.cpp:4156:11
#56 nsRefreshDriver::Tick(mozilla::layers::BaseTransactionId<mozilla::VsyncIdType>, mozilla::TimeStamp) src/layout/base/nsRefreshDriver.cpp:2011:20
#57 mozilla::RefreshDriverTimer::TickRefreshDrivers(mozilla::layers::BaseTransactionId<mozilla::VsyncIdType>, mozilla::TimeStamp, nsTArray<RefPtr<nsRefreshDriver> >&) src/layout/base/nsRefreshDriver.cpp:350:7
#58 mozilla::RefreshDriverTimer::Tick(mozilla::layers::BaseTransactionId<mozilla::VsyncIdType>, mozilla::TimeStamp) src/layout/base/nsRefreshDriver.cpp:366:5
#59 mozilla::VsyncRefreshDriverTimer::RefreshDriverVsyncObserver::TickRefreshDriver(mozilla::layers::BaseTransactionId<mozilla::VsyncIdType>, mozilla::TimeStamp) src/layout/base/nsRefreshDriver.cpp:727:16
#60 mozilla::VsyncRefreshDriverTimer::RefreshDriverVsyncObserver::ParentProcessVsyncNotifier::Run() src/layout/base/nsRefreshDriver.cpp:525:20
#61 nsThread::ProcessNextEvent(bool, bool*) src/xpcom/threads/nsThread.cpp:1225:14
#62 NS_ProcessNextEvent(nsIThread*, bool) src/xpcom/threads/nsThreadUtils.cpp:486:10
#63 mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) src/ipc/glue/MessagePump.cpp:88:21
#64 MessageLoop::RunInternal() src/ipc/chromium/src/base/message_loop.cc:315:10
#65 MessageLoop::Run() src/ipc/chromium/src/base/message_loop.cc:290:3
#66 nsBaseAppShell::Run() src/widget/nsBaseAppShell.cpp:137:27
#67 nsAppStartup::Run() src/toolkit/components/startup/nsAppStartup.cpp:276:30
#68 XREMain::XRE_mainRun() src/toolkit/xre/nsAppRunner.cpp:4600:22
#69 XREMain::XRE_main(int, char**, mozilla::BootstrapConfig const&) src/toolkit/xre/nsAppRunner.cpp:4735:8
#70 XRE_main(int, char**, mozilla::BootstrapConfig const&) src/toolkit/xre/nsAppRunner.cpp:4816:21
#71 do_main(int, char**, char**) src/browser/app/nsBrowserApp.cpp:218:22
#72 main src/browser/app/nsBrowserApp.cpp:300:16
Flags: in-testsuite?

Sounds like a bounds problem which would be sec-high unless there's some other mitigating checks in the code.

It's not a bounds issue at the point in gfxSkipChars where this is reported, because the code explicitly checks the offset and clamps it to the limit (after issuing the gfxCriticalError message), so it won't lead to an out-of-bounds access here.

However, it does suggest something is not right - some kind of mismatch between the frames and textruns, maybe - and I'd be concerned the unexpected offset value might end up used in some other place that does result in out-of-bounds access. So we need to get to the root of this and figure out what assumption is being violated.

I see the testcase includes column-span: all, which plausibly might be involved. Tentatively moving the bug to Layout:Columns. Ting-Yu, could you see if this is in fact colspan-related?

Component: Graphics: Text → Layout: Columns
Flags: needinfo?(aethanyc)
Priority: -- → P3

Tyson, does this testcase needs other prefs to trigger the assertion? (column-span has been enabled on Nighty.) I cannot reproduce it with my own debug build with latest m-c on this revision https://hg.mozilla.org/mozilla-central/rev/1dc1a755079a15e35cb234db511e52ab463b2f42

Flags: needinfo?(aethanyc) → needinfo?(twsmith)
Attached file testcase.html

This seems to be a more reliable test case.

Attachment #9093501 - Attachment is obsolete: true
Flags: needinfo?(twsmith)

Thanks Tyson. I can reproduce with the test case in comment 4. When the assertion triggered, I saw there is a lingered "overflow-line" containing a column container in the frame tree dump in my local rr session, which means we do something wrong when fragmenting multi-column. I'll take a look.

Flags: needinfo?(aethanyc)

TYLin: Assigning to you for now since it sounds like you're actively investigating.

Assignee: nobody → aethanyc
See Also: → 1588623

By looking at the original diff, the comments were placed after the conditions.
https://hg.mozilla.org/mozilla-central/diff/854d0d4791411c4733946d366a3824509451ed4f/layout/generic/nsAbsoluteContainingBlock.cpp

I place the comments before the conditions, and add blank lines to
separate them. This is a preparation because Part 2 is going to add a
new condition.

The crashtest contains an absolute positioning <dialog> multicol
container. If it is fragmented, we end up having a very wrong frame
tree.

Depends on D49209

Flags: needinfo?(aethanyc)
Group: layout-core-security
Group: gfx-core-security

I'm assuming that we're OK including a crashtest up-front for both of the following reasons:
(a) it sounds like we're not doing anything obviously-exploitable, per comment 2
(b) this depends on column-span being enabled, and it's not enabled beyond Nightly yet (it's riding the 71 release train as of bug 1426010)

Are both of those ^^ correct? If I'm wrong about both (particularly the latter one), then the crashtest would want to wait.

Flags: needinfo?(aethanyc)

Yes, both (a) and (b) are correct. Column-span is not enabled by default in 70, and the test case doesn't crash if column-span is disabled.

Flags: needinfo?(aethanyc)
Group: layout-core-security → core-security-release
Flags: in-testsuite? → in-testsuite+
Flags: qe-verify+
Whiteboard: [post-critsmash-triage]

I have managed to reproduce a crash using the attached test case on an affected build in:

I deem this bug verified. The verification was done on Windows 10 x64.

Status: RESOLVED → VERIFIED
Flags: qe-verify+
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: