diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2022-05-27 21:36:31 +0930 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2022-05-28 06:34:55 +0930 |
commit | a8c1858cf2bb6efb35c0678d135fd522ece9e2a4 (patch) | |
tree | e7b37d5013b2918dac57bb1bacbae00eb82655c4 /src/cairo-scaled-font.c | |
parent | 5dafd7411660f153219abceab64d5cc3be1c59a6 (diff) | |
download | cairo-a8c1858cf2bb6efb35c0678d135fd522ece9e2a4.tar.gz |
Fix deadlock in cairo-scaled-font.c
When cairo_scaled_glyph_page_cache needs to remove entries,
cairo-cache calls _cairo_hash_table_random_entry() with the predicate
_cairo_scaled_glyph_page_can_remove(). This function checks that the
glyph_page scaled_font is not locked by testing
scaled_font->cache_frozen. The scaled font is locked in the
cache-cache destroy entry callback: _cairo_scaled_glyph_page_pluck().
There is a race condition here between testing
scaled_font->cache_frozen and locking the font. Fix this by adding a
new CAIRO_MUTEX_TRY_LOCK mutex operation, and using it to test and
lock the scaled font in _cairo_scaled_glyph_page_can_remove().
Fixes the multithreaded case in #440
Diffstat (limited to 'src/cairo-scaled-font.c')
-rwxr-xr-x | src/cairo-scaled-font.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index 203b6a10c..4000a7082 100755 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -476,7 +476,7 @@ _cairo_scaled_glyph_page_pluck (void *closure) scaled_font = page->scaled_font; - CAIRO_MUTEX_LOCK (scaled_font->mutex); + /* The font is locked in _cairo_scaled_glyph_page_can_remove () */ _cairo_scaled_glyph_page_destroy (scaled_font, page); CAIRO_MUTEX_UNLOCK (scaled_font->mutex); } @@ -2855,14 +2855,17 @@ _cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph, scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; } +/* _cairo_hash_table_random_entry () predicate. To avoid race conditions, + * the font is locked when tested. The font is unlocked in + * _cairo_scaled_glyph_page_pluck. */ static cairo_bool_t _cairo_scaled_glyph_page_can_remove (const void *closure) { const cairo_scaled_glyph_page_t *page = closure; - const cairo_scaled_font_t *scaled_font; + cairo_scaled_font_t *scaled_font; scaled_font = page->scaled_font; - return scaled_font->cache_frozen == 0; + return CAIRO_MUTEX_TRY_LOCK (scaled_font->mutex); } static cairo_status_t |