A memory leak in FT_New_Size() upon error doing the class init_size()...
Migrated from: [SAVANNAH-58611]
Sebastian Rasmussen reported:
A bug in a similar situation as #58609 and #58610 was found in FreeType 2.10.0. This was found using gcc 9.3.0 ASAN and a custom allocator that lets me control when/where it will return NULL.
This is the gdb backtrace (relevant for Freetype) where the allocator returns NULL:
#1 (closed) 0x0000555555b1c22d in ft_mem_qalloc (memory=0x621000002920, size=2056,
p_error=0x7fffffff8f90) at freetype/src/base/ftutil.c:76
#2 (closed) 0x0000555555b1c0b2 in ft_mem_alloc (memory=0x621000002920, size=2056,
p_error=0x7fffffff9060) at freetype/src/base/ftutil.c:55
#3 (closed) 0x0000555555b46697 in cff_size_init (cffsize=0x60b0000003c0)
at freetype/src/cff/cffobjs.c:181
#4 (closed) 0x0000555555b03caa in FT_New_Size (face=0x61a000000c90,
asize=0x7fffffff9380) at freetype/src/base/ftobjs.c:2847
#5 (closed) 0x0000555555b026b2 in ft_open_face_internal (library=0x614000000450,
args=0x7fffffff9420, face_index=0, aface=0x7fffffff9530,
test_mac_fonts=1 '\001') at freetype/src/base/ftobjs.c:2575
#6 (closed) 0x0000555555b01bb2 in FT_New_Memory_Face (library=0x614000000450,
file_base=0x55555668c7db "\001", file_size=34024, face_index=0,
aface=0x7fffffff9530) at freetype/src/base/ftobjs.c:1493
This is the corresponding backtrace where the allocation of the data that leaks occurs:
#1 (closed) 0x55adf965e22c in ft_mem_qalloc freetype/src/base/ftutil.c:76
#2 (closed) 0x55adf965e0b1 in ft_mem_alloc freetype/src/base/ftutil.c:55
#3 (closed) 0x55adf9645bee in FT_New_Size freetype/src/base/ftobjs.c:2841
#4 (closed) 0x55adf96446b1 in ft_open_face_internal freetype/src/base/ftobjs.c:2575
#5 (closed) 0x55adf9643bb1 in FT_New_Memory_Face freetype/src/base/ftobjs.c:1493
By looking at the source (https://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/base/ftobjs.c#n2840)
it is evident that internal is never freed if clazz->init_size() returns an error:
if ( FT_NEW( internal ) )
goto Exit,
size->internal = internal,
if ( clazz->init_size )
error = clazz->init_size( size ),
/* ... */
Exit:
if ( error )
{
FT_FREE( node ),
FT_FREE( size ),
}
return error,
}
I will attach my proposed solution for this bug shortly. I have tested
this patch and I see no other leaks after applying it.