fix use after free in font caching algorithm

Current font caching algorithm contains a use after free error. A font
removed from `frc` might be still listed in `wx.specbuf`. It will lead
to a crash inside `XftDrawGlyphFontSpec()`.

Steps to reproduce:
$ st -f 'Misc Tamsyn:scalable=false'
$ curl https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt

Of course, result depends on fonts installed on a system and fontconfig.
In my case, I'm getting consistent segfaults with different fonts.

I replaced a fixed array with a simple unbounded buffer with a constant
growth rate. Cache starts with a capacity of 0, gets increments by 16,
and never shrinks. On my machine after `cat UTF-8-demo.txt` buffer
reaches a capacity of 192. During casual use capacity stays at 0.
This commit is contained in:
magras 2019-02-28 04:56:01 +03:00 committed by Hiltjo Posthuma
parent e85b6b6466
commit a8cb8e9454

15
x.c
View File

@ -226,8 +226,9 @@ typedef struct {
} Fontcache; } Fontcache;
/* Fontcache is an array now. A new font will be appended to the array. */ /* Fontcache is an array now. A new font will be appended to the array. */
static Fontcache frc[16]; static Fontcache *frc = NULL;
static int frclen = 0; static int frclen = 0;
static int frccap = 0;
static char *usedfont = NULL; static char *usedfont = NULL;
static double usedfontsize = 0; static double usedfontsize = 0;
static double defaultfontsize = 0; static double defaultfontsize = 0;
@ -1244,12 +1245,14 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
fcpattern, &fcres); fcpattern, &fcres);
/* /*
* Overwrite or create the new cache entry. * Allocate memory for the new cache entry.
*/ */
if (frclen >= LEN(frc)) { if (frclen >= frccap) {
frclen = LEN(frc) - 1; frccap += 16;
XftFontClose(xw.dpy, frc[frclen].font); if (!frc)
frc[frclen].unicodep = 0; frc = xmalloc(frccap * sizeof(Fontcache));
else
frc = xrealloc(frc, frccap * sizeof(Fontcache));
} }
frc[frclen].font = XftFontOpenPattern(xw.dpy, frc[frclen].font = XftFontOpenPattern(xw.dpy,