fix use after free in font caching algorithm - st - Personal fork of st
 (HTM) git clone git://git.drkhsh.at/st.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit a8cb8e94547d7e31441d2444e8a196415e3e4c1f
 (DIR) parent e85b6b64660214121164ea97fb098eaa4935f7db
 (HTM) Author: magras <dr.magras@gmail.com>
       Date:   Thu, 28 Feb 2019 04:56:01 +0300
       
       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.
       
       Diffstat:
         M x.c                                 |      15 +++++++++------
       
       1 file changed, 9 insertions(+), 6 deletions(-)
       ---
 (DIR) diff --git a/x.c b/x.c
       @@ -226,8 +226,9 @@ typedef struct {
        } Fontcache;
        
        /* 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 frccap = 0;
        static char *usedfont = NULL;
        static double usedfontsize = 0;
        static double defaultfontsize = 0;
       @@ -1244,12 +1245,14 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
                                                fcpattern, &fcres);
        
                                /*
       -                         * Overwrite or create the new cache entry.
       +                         * Allocate memory for the new cache entry.
                                 */
       -                        if (frclen >= LEN(frc)) {
       -                                frclen = LEN(frc) - 1;
       -                                XftFontClose(xw.dpy, frc[frclen].font);
       -                                frc[frclen].unicodep = 0;
       +                        if (frclen >= frccap) {
       +                                frccap += 16;
       +                                if (!frc)
       +                                        frc = xmalloc(frccap * sizeof(Fontcache));
       +                                else
       +                                        frc = xrealloc(frc, frccap * sizeof(Fontcache));
                                }
        
                                frc[frclen].font = XftFontOpenPattern(xw.dpy,