Menu

#1828 possible tk-crash for font-problems

obsolete: 8.5.1
open
7
2008-03-12
2004-12-23
No

File: tk/unix/tkUnixRFont.c

Function GetFont() calls
XftFontOpenPattern(...), which under some circumstances
*can* return NULL (I'm not sure if this can happen also
under sane conditions, or only on misconfigured systems)
GetFont passes on that pointer unchecked and unused.

Function InitFont() (same file) calls GetFont(), doesn't
check for NULL and dereferences the pointer.
This is where the crash happens.

Btw., function Tk_MeasureChars() also calls GetFont()
and passes its result directly to XftTextExtents32().
Whether the latter deals correctly with NULL-pointers
should be checked.

In Tk_DrawChars() the return-value of GetFont() is
correctly checked for NULL.

Discussion

1 2 > >> (Page 1 of 2)
  • Jeffrey Hobbs

    Jeffrey Hobbs - 2004-12-23
    • milestone: --> 387208
    • assigned_to: hobbs --> jenglish
    • priority: 5 --> 7
     
  • Joe English

    Joe English - 2004-12-24

    Logged In: YES
    user_id=68433

    From earlier reports
    (slrncsfqms.g0f.avl@gamma.logic.tuwien.ac.at):

    (gdb) bt
    #0 0xb7f663ba in InitFont () from /usr/local/lib/libtk8.5.so
    #1 0xb7f667ec in TkpGetFontFromAttributes () from
    /usr/local/lib/libtk8.5.so
    #2 0xb7f34717 in Tk_AllocFontFromObj () from
    /usr/local/lib/libtk8.5.so
    #3 0xb7f2cde3 in DoObjConfig () from /usr/local/lib/libtk8.5.so
    #4 0xb7f2d091 in Tk_SetOptions () from
    /usr/local/lib/libtk8.5.so
    #5 0xb7f67447 in ConfigureButton () from
    /usr/local/lib/libtk8.5.so

    and <slrncsiet1.g0f.avl@gamma.logic.tuwien.ac.at>:
    #0 0xb7f4d3fa in InitFont (tkwin=0x8159438, pattern=0x821f0f8,
    fontPtr=0x8159738) at .../tk/unix/tkUnixRFont.c:187
    187 if (XftPatternGetString(ftFont->pattern,
    XFT_FAMILY, 0,

     
  • Joe English

    Joe English - 2004-12-24

    Logged In: YES
    user_id=68433

    Trouble is, at this point in the call sequence there's no
    good way to signal an error. TkpGetFontFromAttributes()
    can't return NULL, since the call sites in generic/tkFont.c
    expect that it always succeeds.

    And on the other end, it looks like FcFontRenderPrepare() is
    always expected to succeed as well. Need to dig deeper into
    the Xft documentation (such as it is...) to see if this is
    really the case.

     
  • Nobody/Anonymous

    Logged In: NO

    Maybe a dumb suggestion, but would it be possible to
    attempt to fall back to some default font and return that,
    And if even that fails, well it can't get worse than SEGV.

    Lateron this could be extended to successively drop some
    of user's wishes until a font can be found. Perhaps, even
    falling back to core X fonts may be an option.

     
  • Joe English

    Joe English - 2005-01-10
    • priority: 7 --> 3
     
  • Joe English

    Joe English - 2005-01-10

    Logged In: YES
    user_id=68433

    More info:

    FcFontRenderPrepare can return NULL, although AFAICT it only
    does so in exceptional circumstances (out-of-memory,
    internal misconfiguration).

    XftFontOpenPattern() can return NULL if there is no
    matching font; however, in this case the pattern in question
    came from FcFontSort(), which AFAICT returns a list of
    _available_ fonts. So it ought to match.

    This looks like a "Can't happen" circumstance; leaving alone
    for now since according to the original bug report on c.l.t.
    this was happening on a system known to be misconfigured.
    However, there are some other problems related to the Tk end
    of things (see #800149) that I'm also investigating, after
    fixing those things should be more robust.

     
  • Nobody/Anonymous

    Logged In: NO

    I'm avl42 (logging in didn't seem to work)

    There is some new/extra information:
    My system is still Debian (woody then, now sarge), and the
    misconfigured parts should be cleaned up by now.
    My "wish8.5" has been configured with --enable-xft,
    and on my system I "reconfigure" (using debian tools) the
    package "fontconfig":
    If I configure it to to use bitmap-fonts, and run a script that
    uses {Helvetica 18} then wish crashes. If I setup fontconfig
    not to use bitmapped fonts, then wish works, but the fonts
    look lousy on my TFT.

    I'd like to see it re-prioritized to at least 7.

    As a solution, it would still be better to fall back to some default
    font (e.g. fixed), than crash with a segfault. (see original post)

     
  • Joe English

    Joe English - 2005-06-10

    Logged In: YES
    user_id=68433

    Thanks for the followup. I'm also running Debian Sarge (or
    almost-sarge), but still can't reproduce the problem.

    I enabled bitmap fonts with dpkg-reconfigure; here's (what
    seem to be) the relevant parts of
    /var/cache/debconf/config.dat, does this match your system?

    | Name: fontconfig/enable_bitmaps
    | Value: true
    | Name: fontconfig/hinting_type
    | Value: Autohinter
    | Name: fontconfig/rendering_type
    | Value: Autohinter
    | Name: fontconfig/subpixel_rendering
    | Value: Automatic

    I just tried a simple test script, 'pack [label .l -text Foo
    -font {Helvetica 18}]'. This us definitely using a
    bitmapped font now, but fails to crash ...

    Does that script crash for you? If not, can you post one
    that does?

     
  • Joe English

    Joe English - 2005-06-10
    • milestone: 387208 --> 455019
    • priority: 3 --> 7
     
  • Andreas Leitgeb

    Andreas Leitgeb - 2005-06-12

    Logged In: YES
    user_id=830354

    I don't seem to find a way to set the rendering_type using debconf
    (although debconf level is set to lowest), which is
    "Bytecode interpreter (CRT screens)" in my case, all others are
    now like you described. and the script you suggested crashes
    with a segfault. (it says, "Speicherzugriffsfehler", which is german
    for "Segmentation fault"), and the exact location has already been
    mentioned in this thread.
    Hmm, perhaps there is still something left from my previously
    broken system.
    Anyway, other applications don't crash when using the same fonts, and
    there must be something that can be done better than dereference a
    possibly-NULL pointer.

     
  • Joe English

    Joe English - 2007-06-26

    Logged In: YES
    user_id=68433
    Originator: NO

    Reported on the Tcl'ers chat:

    | I think I just ran into bug # 1090382 with the font I downloaded from
    | http://img.dafont.com/download/?os=win&file=graffiti_treat, in case you are still
    | looking for a way to reproduce the problem

    Still cannot replicate here though.

     
  • Joe English

    Joe English - 2007-10-11

    Logged In: YES
    user_id=68433
    Originator: NO

    Same problem reported again on the Tcl'ers chat (System: NetBSD, right after an upgrade from 4.0-beta2 to 4.0-RC2).

    After a long debugging session, turned out that running `fc-cache -fv` as root made the problem go away.

     
  • Joe English

    Joe English - 2007-10-11

    Logged In: YES
    user_id=68433
    Originator: NO

    More info: the failure path was: in GetFont, FcFontRenderPrepare() returned a non-NULL pattern, but passing that to XftFontOpenPattern() returned NULL.

     
  • Joe English

    Joe English - 2008-02-14

    Logged In: YES
    user_id=68433
    Originator: NO

    See also Debian bug #465462.

     
  • Joe English

    Joe English - 2008-02-14
    • milestone: 455019 --> obsolete: 8.5.1
     
  • Sergei Golovan

    Sergei Golovan - 2008-02-15

    Logged In: YES
    user_id=410366
    Originator: NO

    Attached font.diff is proof-of-concept patch which 1) runs through the whole set of subfonts returned by FcFontSort() (caching failures to minimise XftFontOpenPattern() calls); 2) tries to load "sans" font as a fallback. I hope that the idea will be useful.

     
  • Sergei Golovan

    Sergei Golovan - 2008-02-15

    Logged In: YES
    user_id=410366
    Originator: NO

    Hm. Cannot attach a file. Including it here:

    --- unix/tkUnixRFont.c.orig 2008-02-14 21:38:54.000000000 +0300
    +++ unix/tkUnixRFont.c 2008-02-15 22:37:06.000000000 +0300
    @@ -20,6 +20,7 @@
    XftFont *ftFont;
    FcPattern *source;
    FcCharSet *charset;
    + int failed;
    } UnixFtFace;

    typedef struct {
    @@ -60,6 +61,31 @@
    }

    static XftFont *
    +GetFontFallback(
    + UnixFtFont *fontPtr)
    +{
    + double size;
    + int pxsize;
    + char *type;
    +
    + if (XftPatternGetDouble(fontPtr->pattern, XFT_SIZE, 0,
    + &size) == XftResultMatch) {
    + type = XFT_SIZE;
    + } else if (XftPatternGetInteger(fontPtr->pattern, XFT_PIXEL_SIZE, 0,
    + &pxsize) == XftResultMatch) {
    + type = XFT_PIXEL_SIZE;
    + size = pxsize;
    + } else {
    + type = XFT_SIZE;
    + size = 12.0;
    + }
    + return XftFontOpen(fontPtr->display, fontPtr->screen,
    + FC_FAMILY, FcTypeString, "sans",
    + type, XftTypeDouble, size,
    + NULL);
    +}
    +
    +static XftFont *
    GetFont(
    UnixFtFont *fontPtr,
    FcChar32 ucs4)
    @@ -69,23 +95,57 @@
    if (ucs4) {
    for (i = 0; i < fontPtr->nfaces; i++) {
    FcCharSet *charset = fontPtr->faces[i].charset;
    - if (charset && FcCharSetHasChar(charset, ucs4)) {
    - break;
    + if (!(charset && FcCharSetHasChar(charset, ucs4))) {
    + continue;
    + }
    + if (fontPtr->faces[i].ftFont) {
    + return fontPtr->faces[i].ftFont;
    + } else {
    + if (!fontPtr->faces[i].failed) {
    + FcPattern *pat = FcFontRenderPrepare(0, fontPtr->pattern,
    + fontPtr->faces[i].source);
    +
    + fontPtr->faces[i].ftFont = XftFontOpenPattern(fontPtr->display, pat);
    + }
    + if (fontPtr->faces[i].ftFont) {
    + return fontPtr->faces[i].ftFont;
    + } else {
    + fontPtr->faces[i].failed = 1;
    + }
    }
    }
    - if (i == fontPtr->nfaces) {
    - i = 0;
    + }
    +
    + for (i = 0; i < fontPtr->nfaces; i++) {
    + if (fontPtr->faces[i].ftFont) {
    + return fontPtr->faces[i].ftFont;
    + } else {
    + if (!fontPtr->faces[i].failed) {
    + FcPattern *pat = FcFontRenderPrepare(0, fontPtr->pattern,
    + fontPtr->faces[i].source);
    +
    + fontPtr->faces[i].ftFont = XftFontOpenPattern(fontPtr->display, pat);
    + }
    + if (fontPtr->faces[i].ftFont) {
    + return fontPtr->faces[i].ftFont;
    + } else {
    + fontPtr->faces[i].failed = 1;
    + }
    }
    - } else {
    - i = 0;
    }
    - if (!fontPtr->faces[i].ftFont) {
    - FcPattern *pat = FcFontRenderPrepare(0, fontPtr->pattern,
    - fontPtr->faces[i].source);

    - fontPtr->faces[i].ftFont = XftFontOpenPattern(fontPtr->display, pat);
    + if (fontPtr->faces[fontPtr->nfaces].ftFont) {
    + return fontPtr->faces[fontPtr->nfaces].ftFont;
    + } else {
    + fontPtr->faces[fontPtr->nfaces].ftFont = GetFontFallback(fontPtr);
    + if (fontPtr->faces[fontPtr->nfaces].ftFont) {
    + return fontPtr->faces[fontPtr->nfaces].ftFont;
    + } else {
    + Tcl_Panic("Cannot find a usable font. Check your fontconfig settings");
    + /* Never reached */
    + return NULL;
    + }
    }
    - return fontPtr->faces[i].ftFont;
    }

    /*
    @@ -184,7 +244,7 @@
    FcCharSet *charset;
    FcResult result;
    XftFont *ftFont;
    - int i;
    + int i, nfont;

    if (!fontPtr) {
    fontPtr = (UnixFtFont *) ckalloc(sizeof(UnixFtFont));
    @@ -199,21 +259,22 @@

    set = FcFontSort(0, pattern, FcTrue, NULL, &result);
    if (!set) {
    - FcPatternDestroy(pattern);
    - ckfree((char *)fontPtr);
    - return NULL;
    + nfont = 0;
    + } else {
    + nfont = set->nfont;
    }

    fontPtr->fontset = set;
    fontPtr->pattern = pattern;
    - fontPtr->faces = (UnixFtFace *) ckalloc(set->nfont * sizeof(UnixFtFace));
    - fontPtr->nfaces = set->nfont;
    + /* Extra slot for possible fallback */
    + fontPtr->faces = (UnixFtFace *) ckalloc((nfont + 1) * sizeof(UnixFtFace));
    + fontPtr->nfaces = nfont;

    /*
    * Fill in information about each returned font
    */

    - for (i = 0; i < set->nfont; i++) {
    + for (i = 0; i < nfont; i++) {
    fontPtr->faces[i].ftFont = 0;
    fontPtr->faces[i].source = set->fonts[i];
    if (FcPatternGetCharSet(set->fonts[i], FC_CHARSET, 0,
    @@ -222,7 +283,13 @@
    } else {
    fontPtr->faces[i].charset = 0;
    }
    + fontPtr->faces[i].failed = 0;
    }
    + /* Fill in a fallback slot */
    + fontPtr->faces[nfont].ftFont = 0;
    + fontPtr->faces[nfont].source = 0;
    + fontPtr->faces[nfont].charset = 0;
    + fontPtr->faces[nfont].failed = 0;

    fontPtr->display = Tk_Display(tkwin);
    fontPtr->screen = Tk_ScreenNumber(tkwin);
    @@ -253,7 +320,7 @@
    Tk_ErrorHandler handler = Tk_CreateErrorHandler(display, -1, -1, -1, NULL,
    (ClientData) NULL);

    - for (i = 0; i < fontPtr->nfaces; i++) {
    + for (i = 0; i <= fontPtr->nfaces; i++) {
    if (fontPtr->faces[i].ftFont) {
    XftFontClose(fontPtr->display, fontPtr->faces[i].ftFont);
    }

     
  • Joe English

    Joe English - 2008-02-21

    Logged In: YES
    user_id=68433
    Originator: NO

    More info: reported on the Tcl'ers chat:

    This problem affects Tk on NetBSD, where the base system includes one version of Xft and another is available through pkgsrc. Tk picks up the base version, because the configure script tries (old, obsolete) `xft-config` first, and only checks (new, recommended) `pkg-config` second. Other toolkits that use the xft/fontconfig libs installed with pkgsrc do not have a problem; however xterm and a few others (which use the libs from the base system) are also prone to dumping core (`xterm -fa bitstream` is reported to crash, for example).

     
  • Don Porter

    Don Porter - 2008-02-25

    Logged In: YES
    user_id=80530
    Originator: NO

    here is the workaround patch
    from teopetuk in the form of
    an attached file generated
    by `cvs diff`

    The patch stops the segfault
    problem for me.
    File Added: 1090382.patch

     
  • Don Porter

    Don Porter - 2008-02-25
     
  • Don Porter

    Don Porter - 2008-03-06

    Logged In: YES
    user_id=80530
    Originator: NO

    The Tk HEAD crashes in
    canvText.test on my
    CentOS 5 system. I'd like
    to release Tk 8.5.2 soon, but
    this crash limits my testing
    ability, and gives me pause.

     
  • Don Porter

    Don Porter - 2008-03-06
    • priority: 7 --> 9
     
  • Don Porter

    Don Porter - 2008-03-06

    Logged In: YES
    user_id=80530
    Originator: NO

    Stack trace for the crash:

    Program received signal SIGSEGV, Segmentation fault.
    0x080f5914 in GetTkFontAttributes (ftFont=0x0, faPtr=0x8a220c4)
    at /home/dgp/cvs/tk/unix/../unix/tkUnixRFont.c:107
    107 (void)XftPatternGetString(ftFont->pattern, XFT_FAMILY, 0, familyPtr);
    (gdb) bt
    #0 0x080f5914 in GetTkFontAttributes (ftFont=0x0, faPtr=0x8a220c4)
    at /home/dgp/cvs/tk/unix/../unix/tkUnixRFont.c:107
    #1 0x080f5d54 in InitFont (tkwin=0x8824360, pattern=0x8a21388,
    fontPtr=0x8a220a0) at /home/dgp/cvs/tk/unix/../unix/tkUnixRFont.c:241
    #2 0x080f5f55 in TkpGetNativeFont (tkwin=0x8824360,
    name=0x8a21da8 "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*")
    at /home/dgp/cvs/tk/unix/../unix/tkUnixRFont.c:303
    #3 0x081230c2 in Tk_AllocFontFromObj (interp=0x87c5628, tkwin=0x8824360,
    objPtr=0x89fdcd8) at /home/dgp/cvs/tk/unix/../generic/tkFont.c:1175
    #4 0x081227fc in Tk_FontObjCmd (clientData=0x8824360, interp=0x87c5628,
    objc=4, objv=0x88d29a4) at /home/dgp/cvs/tk/unix/../generic/tkFont.c:761
    #5 0x08153a8a in TclEvalObjvInternal (interp=0x87c5628, objc=4,
    objv=0x88d29a4,
    command=0x89b0a1e "font metrics $font -linespace]\nset ax [font measure $font 0]\n\n\nforeach test {\n {-anchor nw nw xyz {bad anchor position \"xyz\": must be n, ne, e, se, s, sw, w, nw, or center}}\n {-fill #ff0000 #ff0"...,
    length=29, flags=0) at /home/dgp/cvs/tcl/unix/../generic/tclBasic.c:3650

    Appears that ftFont is NULL when it must not be.

     
  • Joe English

    Joe English - 2008-03-06

    Logged In: YES
    user_id=68433
    Originator: NO

    dgp reports: canvTest.text segfaults at line 23.

    One other thing to try: env FC_DEBUG=129 ./wish8.5
    entry .e
    # fontconfig should spit out a bunch of diagnostic info
    .e configure -font -adobe-times-medium-r-normal--*-200-*-*-*-*-*-*
    # ... and some more here.
    # ... then you should segfault.

    The problem is almost certainly due to a misconfigured font cache. `fc-cache -fv` usually fixes it, but _don't do that yet_ -- catching this thing in the wild is difficult.

    I'd like to try a simpler patch (in preparation) to see if that fixes the problem.

     
  • Joe English

    Joe English - 2008-03-12

    Logged In: YES
    user_id=68433
    Originator: NO

    Attached patch tk-xft-crash-1.patch takes a more conservative approach. It adds a fallback case to GetFont(), but omits all the "try harder" logic. I believe this will avoid the crashes dgp is observing. It does not account for cases where FcFontSort() fails.

    File Added: tk-xft-crash-1.patch

     
1 2 > >> (Page 1 of 2)