freemint / fvdi

fVDI fork with additional fixes and drivers.
https://fvdi.sourceforge.io
7 stars 6 forks source link

Font autohinting causes crashes #16

Open chrisridd opened 2 years ago

chrisridd commented 2 years ago

The free "SourceSans3-ExtraLight.ttf" file from Adobe's github causes freemint to crash the entire machine with:

pid  16 (desktop): halt: coprocessor protocol violation
FATAL ERROR. You must reboot the system.

My FVDI build of master is using Freetype 2.10.2. The crashing app is iterating across all loaded fonts and doing this:

fontid = vqt_name(handle, i, fontname);
vst_font(handle, fontid);

/* is proportional? */
vst_point(handle, 10, &dummy, &dummy, &dummy, &dummy);
vqt_width(handle, 'i', &iwidth, &dummy, &dummy);

which is simulating the font selector in Teradesk - which then does a vqt_width(.. 'm'..) to check if this is a proportional font. Obviously there are other ways to do that check, but vqt_width() should not crash the machine.

This works fine on other TTFs I'm using.

Some copious logging later reveals it to be crashing in ft2_load_glyph() when it calls FT_Load_Glyph(). I wrote a quick and dirty Mac application making the same sequence of calls directly against Freetype 2.11.1, and it did not crash. I think we're passing the correct glyph index in.

I'm not entirely sure how to proceed. Is there a way to get a fuller stack trace out of aranym + freemint?

Possibly updating FVDI to 2.11.x would help?

chrisridd commented 2 years ago

I discovered this also happens with at least one Type 1 font from CTAN.

I tested with cmb10.pfb and the same sequence of calls either crashed or hung freemint.

chrisridd commented 2 years ago

It looks like FT_Load_Glyph() is calling itself recursively for "Source Sans 3", because it is autohinting for that font - and not autohinting for the other TTF fonts I have installed. That other crashing font I found - cmb10 - also wants to be autohinted.

The freetype ftobjs.c code has this interesting comment:

    /*
     * Determine whether we need to auto-hint or not.
     * The general rules are:
     *
     * - Do only auto-hinting if we have
     *
     *   - a hinter module,
     *   - a scalable font,
     *   - not a tricky font, and
     *   - no transforms except simple slants and/or rotations by
     *     integer multiples of 90 degrees.
     *
     * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
     *   have a native font hinter.
     *
     * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't
     *   any hinting bytecode in the TrueType/OpenType font.
     *
     * - Exception: The font is `tricky' and requires the native hinter to
     *   load properly.
     */

If I change the single call in module/ft2/ft2.c to FT_Load_Glyph() from FT_LOAD_DEFAULT to FT_LOAD_NO_AUTOHINT:

    error = FT_Load_Glyph(face, cached->index, FT_LOAD_NO_AUTOHINT);

vqt_width() no longer crashes, and things like qed's Options>Font menu works. However, the "Source Sans 3" font displays absolutely terribly even at larger sizes, and is basically illegible.

mfro0 commented 2 years ago

Could potentially be caused by a stack overflow, as it sounds. Try if increasing fVDI's stack size helps, maybe?

chrisridd commented 2 years ago

I thought the same thing. But I changed to vdi_stack[16384] (from 8192) in startup.c and got the same error. Or is there another way to bump the stack?

objdump from cross tools reports fvdi.prg using 0 stack, which I couldn't understand without going into the gcc startup code rathole!

There are some other FT_LOAD_* flags which help, and at least give better output. Still not good enough output IMO, but more experiments might indeed find a more optimal set of load flags.

chrisridd commented 2 years ago

I noticed that NVDI 5 just refuses to load the file, so maybe that's an option.

mfro0 commented 2 years ago

objdump from cross tools reports fvdi.prg using 0 stack, which I couldn't understand without going into the gcc startup code rathole!

As a special type of TSR that must be able to allocate memory, fVDI can't use the "normal" TOS/MiNT mechanisms for memory allocation (it tries hard to keep ownership to allocated memory, even if the allocation happens in the context of a user application). I've learned it's better keep my hands off of these black art mechanisms ;)

I noticed that NVDI 5 just refuses to load the file, so maybe that's an option.

Sounds like a reasonable approach. If NVDI can't load it, we probably shouldn't try either.