From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleaut32/typelib.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index fa512184182..7fa7eeedfdc 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -3273,6 +3273,32 @@ static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLengt return TYPE_E_CANTLOADLIBRARY; }
+/* + * Safely increment the reference count of a typelib obtained from the typelib + * cache list. + * + * This function shall be called inside the typelib cache's critical section. + */ +static LONG typelib_addref_if_alive(ITypeLibImpl *This) +{ + LONG refs = ReadNoFence(&This->ref); + LONG old_refs, new_refs; + + do + { + if (refs == 0) + { + /* This typelib is about to be destroyed. */ + return 0; + } + + old_refs = refs; + new_refs = refs + 1; + } while ((refs = InterlockedCompareExchange(&This->ref, new_refs, old_refs)) != old_refs); + + return new_refs; +} + /**************************************************************************** * TLB_ReadTypeLib * @@ -3337,11 +3363,10 @@ static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath EnterCriticalSection(&cache_section); LIST_FOR_EACH_ENTRY(entry, &tlb_cache, ITypeLibImpl, entry) { - if (!wcsicmp(entry->path, pszPath) && entry->index == index) + if (!wcsicmp(entry->path, pszPath) && entry->index == index && typelib_addref_if_alive(entry)) { TRACE("cache hit\n"); *ppTypeLib = &entry->ITypeLib2_iface; - ITypeLib2_AddRef(*ppTypeLib); LeaveCriticalSection(&cache_section); return S_OK; } @@ -7955,11 +7980,11 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( && entry->ver_major == ref_type->pImpTLInfo->wVersionMajor && entry->ver_minor == ref_type->pImpTLInfo->wVersionMinor && entry->set_lcid == ref_type->pImpTLInfo->lcid - && entry->syskind == This->pTypeLib->syskind) + && entry->syskind == This->pTypeLib->syskind + && typelib_addref_if_alive(entry)) { TRACE("got cached %p\n", entry); pTLib = (ITypeLib*)&entry->ITypeLib2_iface; - ITypeLib_AddRef(pTLib); result = S_OK; break; }