Closed Bug 1011348 Opened 5 years ago Closed 4 years ago

Crash/freeze when rendering certain private-use characters at font-sizes greater than about 1300%

Categories

(Core :: Graphics, defect)

29 Branch
x86_64
Linux
defect
Not set

Tracking

()

RESOLVED FIXED

People

(Reporter: david, Assigned: nical)

References

Details

(Keywords: crash)

Crash Data

Attachments

(2 files)

See this demo page at https://www.bamsoftware.com/sec/U+EFF2-slider.html (also attached). Look at the page in Firefox on GNU/Linux. Increase the font-size with the slider. At about 1497%, the page rendering freezes and sometimes the browser crashes.

When the font-size is large enough, the browser tab stops repainting and you can see trails if you drag another window over it. You can still interact with the browser chrome, and hover over and click links. Sometimes the page turns all or mostly black. Highlighting and dragging over the frozen page does strange things: sometimes it looks as if the text on the page became an image, and you can drag the whole image away from the browser window.

The error happens only with certain characters, and may depend on what fonts are installed. I had problems with U+EFF2 in the Junicode font (this is what's on the demo page), and U+E044, U+E047, and U+E049 in Linux Libertine. There may be more.

Occasionally the browser crashes, but not predictably. I seem to be able to provoke a crash with much highlighting and dragging, or refreshing and freezing the page several times. Here are a couple of crash reports from the URL above:
bp-c0c55944-11d8-478d-9459-3a57b2140516
bp-4eae13bc-1b0c-48c9-8c8d-5aaa52140516

This looks very similar to bug 611563, but it's marked fixed since 2010, and the HTML page attached there doesn't crash Firefox for me, even if I increase the zoom to maximum. I also only have a problem with a few code points in the private use area, not all of them. (611563 said there was a freeze with at least all of U+E000 through U+E121.)

I wasn't able to reproduce the problem on Windows. I didn't try on OS X.

In Chromium 33 on GNU/Linux, I can increase the font-size to 2000% without a problem. Firefox also has no problem with most characters.

I checked the security box just because of the crash; I didn't verify that the problem is exploitable beyond crashing.
The crash reports show a stack starting with

gfxContext::PushClipsToDT(mozilla::gfx::DrawTarget*)
gfxContext::PushGroup(gfxContentType)
mozilla::layers::BasicLayerManager::PushGroupWithCachedSurface(gfxContext*, gfxContentType)
mozilla::layers::BasicLayerManager::PushGroupForLayer(gfxContext*, mozilla::layers::Layer*, nsIntRegion const&, bool*)
mozilla::layers::BasicLayerManager::PaintLayer(gfxContext*, mozilla::layers::Layer*, void (*)(mozilla::layers::ThebesLayer*, gfxContext*, nsIntRegion const&, mozilla::layers::DrawRegionClip, nsIntRegion const&, void*), void*, mozilla::layers::ReadbackProcessor*)
mozilla::layers::BasicLayerManager::PaintSelfOrChildren(mozilla::layers::PaintLayerContext&, gfxContext*)
mozilla::layers::BasicLayerManager::PaintLayer(gfxContext*, mozilla::layers::Layer*, void (*)(mozilla::layers::ThebesLayer*, gfxContext*, nsIntRegion const&, mozilla::layers::DrawRegionClip, nsIntRegion const&, void*), void*, mozilla::layers::ReadbackProcessor*)
mozilla::layers::BasicLayerManager::PaintSelfOrChildren(mozilla::layers::PaintLayerContext&, gfxContext*)
mozilla::layers::BasicLayerManager::PaintLayer(gfxContext*, mozilla::layers::Layer*, void (*)(mozilla::layers::ThebesLayer*, gfxContext*, nsIntRegion const&, mozilla::layers::DrawRegionClip, nsIntRegion const&, void*), void*, mozilla::layers::ReadbackProcessor*)
mozilla::layers::BasicLayerManager::EndTransactionInternal(void (*)(mozilla::layers::ThebesLayer*, gfxContext*, nsIntRegion const&, mozilla::layers::DrawRegionClip, nsIntRegion const&, void*), void*, mozilla::layers::LayerManager::EndTransactionFlags)
PresShell::Paint(nsView*, nsRegion const&, unsigned int)

which looks to me like this is a Graphics rather than Text problem; likewise, the description ("tab stops repainting" ... "can still interact") sounds like a failure in OpenGL, or something like that. Might turn out to be dependent on the graphics card and/or drivers on the system.

Moving this to Graphics, for the right people to take a look...
Component: Layout: Text → Graphics
Finally we're getting a few ways to reproduce PushClipsToDT!

This doesn't need to be security-private.
Blocks: 805406
Group: core-security
Status: UNCONFIRMED → NEW
Ever confirmed: true
Assignee: nobody → bas
Crash Signature: [@ gfxContext::PushClipsToDT(mozilla::gfx::DrawTarget*) ]
Keywords: crash
This crash does indeed not reproduce on Windows. PushClipsToDT crashes indicate either an out of memory, or a surface creation request that is too large to handle or in some other way refused by cairo (on Linux). Nical, could you have a quick look at which one of this is and what the outside code is doing to get us into that situation, this should be very easy.
Assignee: bas → nical.bugzilla
On an ivybridge linux laptop, I can reproduce the painting problem (ie the page not paiting anymore after a certain value of the slider), but not the crash. This is without OMTC+GL layers. With OMTC I can't reproduce it anymore.
On my haswell linux laptop I can't reproduce any issue anymore (both with and without OMTC).
I don't have the crash and nothing shows up in the log so right now I am putting printfs a little bit everywhere to see if there is code that should be run and ends up not running or if there is anything else suspicious happening around X11 stuff.
Turning off xrender in about config also makes the bug go away, so the issue has to be somewhere in the x11 driver.
Here is the stacktrace of the moment cairo gets into an invalid state. status is set to CAIRO_STATUS_NO_MEMORY in _render_glyph_outline because a few lines above the return statement, FT_Render_Glyph (face->glyph, render_mode) returned 1 (non-zero FT_Error code means an error occurred).
render_mode is equal to FT_RENDER_MODE_LCD
and face->glyph is:

{
  ...
  metrics = {
    width = 16896,
    height = 14592,
    horiBearingX = -64,
    horiBearingY = 11456,
    horiAdvance = 16960,
    vertBearingX = -8576,
    vertBearingY = 4864,
    vertAdvance = 24320
  },
  linearHoriAdvance = 17385984,
  linearVertAdvance = 24879360,
  advance = {
    x = 16960,
    y = 0
  },
  format = FT_GLYPH_FORMAT_OUTLINE,
  bitmap = {
    rows = 228,
    width = 798,
    pitch = 800,
    buffer = 0x0,
    num_grays = 256,
    pixel_mode = 2 '\002',
    palette_mode = 0 '\000',
    palette = 0x0
  },
  bitmap_left = 0,
  bitmap_top = 0,
  outline = {
    n_contours = 5,
    n_points = 138,
    points = 0x7fffc0e47000,
    tags = 0x7fffc0e24000 "\001\001",
    contours = 0x7fffbd3c0250,
    flags = 0
  },
  ...
}

face is constructed upper in the stack like this:
face = _cairo_ft_unscaled_font_lock_face (unscaled);
with unscaled equal to:
{
  ...
  have_scale = 1,
  current_scale = {
    xx = 264,
    yx = 0,
    xy = 0,
    yy = 264,
    x0 = 0,
    y0 = 0
  },
  x_scale = 264,
  y_scale = 264,
  have_shape = 0,
  current_shape = {
    xx = 1,
    yx = 0,
    xy = 0,
    yy = 1,
    x0 = 0,
    y0 = 0
  },
  Current_Shape = {
    xx = 65536, // note that this is equal to max of FT_Signed (16.16 signed)
    xy = 0,
    yx = 0,
    yy = 65536
  },
  ...
}

"..." are the members I left out for readability.

I don't know anything about freetype and cairo's font rendering code but the Current_shape transformation matrix above looks like a fixed point overflow happened somewhere.
(In reply to Nicolas Silva [:nical] from comment #6)
>   Current_Shape = {
>     xx = 65536, // note that this is equal to max of FT_Signed (16.16 signed)
>     xy = 0,
>     yx = 0,
>     yy = 65536
>   },
>   ...
> }
> 
> "..." are the members I left out for readability.
> 
> I don't know anything about freetype and cairo's font rendering code but the
> Current_shape transformation matrix above looks like a fixed point overflow
> happened somewhere.

Are you sure you're interpreting this right? I'd have thought 65536 was simply the 16.16 fixed-point value 1.0 (0x00010000), printed as an integer.

It's still very possible there has been overflow somewhere, but this doesn't look like a smoking gun to me.
(In reply to Jonathan Kew (:jfkthame) from comment #7)
> Are you sure you're interpreting this right? I'd have thought 65536 was
> simply the 16.16 fixed-point value 1.0 (0x00010000), printed as an integer.

D'oh, you are right I trusted gdb to understand the type but it's just an integer underneath.
Crash Signature: [@ gfxContext::PushClipsToDT(mozilla::gfx::DrawTarget*) ] → [@ gfxContext::PushClipsToDT(mozilla::gfx::DrawTarget*) ] [@ gfxContext::PushClipsToDT ]
I think that this got fixed when enabling OMTC on Linux. I can't reproduce anymore on any of my machines. Don't hesitate to reopen if the bug happens again.
Status: NEW → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.