[v5 PATCH 1/3] dwrite: Protect cached fontface list when accessed from multiple threads

Nikolay Sivov bunglehead at gmail.com
Thu Aug 17 13:14:33 CDT 2017


On 17.08.2017 10:40, Sebastian Lackner wrote:
> On 17.08.2017 07:11, Anton Romanov wrote:
>> On Wed, Aug 16, 2017 at 10:05 PM, Anton Romanov <theli.ua at gmail.com> wrote:
>>> On Tue, Aug 15, 2017 at 4:40 AM, Nikolay Sivov <nsivov at codeweavers.com> wrote:
>>>> Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
>>>> ---
>>>>  dlls/dwrite/dwrite_private.h | 15 ++++++++---
>>>>  dlls/dwrite/font.c           | 30 +++++++++++++--------
>>>>  dlls/dwrite/main.c           | 63 +++++++++++++++++++++++++++++++-------------
>>>>  3 files changed, 74 insertions(+), 34 deletions(-)
>>>>
>>> Since apps seem to freely use fontface interfaces from multiple
>>> threads - Isn't the following race possible?
>>>
>>> +----------------+------------------------+-------------------------+
>>> |       T1       |           T2           |           T3            |
>>> +----------------+------------------------+-------------------------+
>>> | Release        |                        |                         |
>>> | Decrement      |                        |                         |
>>> | == 0 -> True   |                        |                         |
>>> |                | Query_Interface/AddRef |                         |
>>> |                | Increment              |                         |
> 
> After the last Release call the app should not be calling any function on
> the object directly.
> 
> The only valid code path to obtain a new reference is going through
> factory_get_cached_fontface. The code in this function is written in such
> a way that it only uses very specific safe methods. Most importantly,
> destroyed font faces are skipped, so for properly written apps no race
> conditions are possible.
> 
>>> |                |                        | Release                 |
>>> |                |                        | Decrement               |
>>> | free(cached)   |                        |                         |
>>> | factory_unlock |                        |                         |
>>> |                |                        | use after free (cached) |
>>> +----------------+------------------------+-------------------------+
>> Actually, with this version of the patch looks like this is exactly
>> the crash I'm consistently getting now (was fine with v1):
>>
>> 0093:trace:dwrite:dwritefontface_Release (0x97936c8)->(1)
>> 0093:trace:dwrite:dwritefontface_Release (0x97936c8)->(0)
>> 004c:trace:dwrite:dwritefontface_GetFiles (0x97936c8)->(0x339d58 0x339d50)
>> 004c:trace:dwrite:dwritefontface_GetIndex (0x97936c8)
>> 004c:trace:dwrite:dwritefontface_TryGetFontTable (0x97936c8)->("GSUB"
>> 0x339e60 0x339e68 0x339e64 0x339e5c)
> 
> It is interesting that there is no "returning cached fontface" in the log
> above. This suggests that your interpretation of the error is wrong, the
> app basically operates on a destroyed object (or there is an error somewhere
> else).
> 
> Does this really work reliable on Windows? If yes it means the current idea
> of thread safety is not really sufficient. Maybe Windows preserves cache
> entries for some specific time (or for the duration of the factory), even
> after the last reference is gone? Or maybe the factory has a reference on
> each font face?

Yes, it's possible there's some MRU list as well. I'm almost sure
factory does not keep a reference, at least not in a way IUnknown
exposes it, I'll need to check if we have tests for that, and maybe add
some.

> 
> 




More information about the wine-devel mailing list