win32u: Guard font unused_entry against race condition.

There is a race condition otherwise between release_gdi_font and
find_cached_gdi_font, leading to invalid memory access:

One thread calling release_gdi_font may decrement refcount to 0,
then try to enter font_lock. At the same time, another thread may be
calling find_cached_gdi_font through select_font, holding the font_lock.

This second thread would find refcount set to 0, and then try to remove
unused_entry from its list, although it hasn't been added yet to the
unused list.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-11-19 12:23:38 +01:00 committed by Alexandre Julliard
parent 162991a03c
commit 39fea6cd1e
1 changed files with 11 additions and 9 deletions

View File

@ -2576,12 +2576,13 @@ static struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *m
static void release_gdi_font( struct gdi_font *font ) static void release_gdi_font( struct gdi_font *font )
{ {
if (!font) return; if (!font) return;
if (--font->refcount) return;
TRACE( "font %p\n", font ); TRACE( "font %p\n", font );
/* add it to the unused list */ /* add it to the unused list */
pthread_mutex_lock( &font_lock ); pthread_mutex_lock( &font_lock );
if (!--font->refcount)
{
list_add_head( &unused_gdi_font_list, &font->unused_entry ); list_add_head( &unused_gdi_font_list, &font->unused_entry );
if (unused_font_count > UNUSED_CACHE_SIZE) if (unused_font_count > UNUSED_CACHE_SIZE)
{ {
@ -2592,6 +2593,7 @@ static void release_gdi_font( struct gdi_font *font )
free_gdi_font( font ); free_gdi_font( font );
} }
else unused_font_count++; else unused_font_count++;
}
pthread_mutex_unlock( &font_lock ); pthread_mutex_unlock( &font_lock );
} }