Commit 8a5886ef authored by Rob Shearman's avatar Rob Shearman Committed by Alexandre Julliard

oleaut32: Fix circular reference counting in typelibs/typeinfos.

Do not rely on the reference count of ITypeInfo's to go to zero to delete them. Instead only rely on the parent typelib's reference count, but update the parent typelib's reference count based on whether each typeinfo has a valid reference.
parent 456ad1b1
...@@ -1048,7 +1048,7 @@ typedef struct tagITypeInfoImpl ...@@ -1048,7 +1048,7 @@ typedef struct tagITypeInfoImpl
const ITypeInfo2Vtbl *lpVtbl; const ITypeInfo2Vtbl *lpVtbl;
const ITypeCompVtbl *lpVtblTypeComp; const ITypeCompVtbl *lpVtblTypeComp;
LONG ref; LONG ref;
BOOL no_free_data; /* don't free data structures */ BOOL not_attached_to_typelib;
TYPEATTR TypeAttr ; /* _lots_ of type information. */ TYPEATTR TypeAttr ; /* _lots_ of type information. */
ITypeLibImpl * pTypeLib; /* back pointer to typelib */ ITypeLibImpl * pTypeLib; /* back pointer to typelib */
int index; /* index in this typelib; */ int index; /* index in this typelib; */
...@@ -1085,6 +1085,7 @@ static const ITypeInfo2Vtbl tinfvt; ...@@ -1085,6 +1085,7 @@ static const ITypeInfo2Vtbl tinfvt;
static const ITypeCompVtbl tcompvt; static const ITypeCompVtbl tcompvt;
static ITypeInfo2 * ITypeInfo_Constructor(void); static ITypeInfo2 * ITypeInfo_Constructor(void);
static void ITypeInfo_fnDestroy(ITypeInfoImpl *This);
typedef struct tagTLBContext typedef struct tagTLBContext
{ {
...@@ -4089,6 +4090,7 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface) ...@@ -4089,6 +4090,7 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
TLBRefType *ref_type; TLBRefType *ref_type;
void *cursor2; void *cursor2;
int i; int i;
ITypeInfoImpl *pTI, *pTINext;
/* remove cache entry */ /* remove cache entry */
if(This->path) if(This->path)
...@@ -4145,8 +4147,11 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface) ...@@ -4145,8 +4147,11 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
TLB_Free(ref_type); TLB_Free(ref_type);
} }
if (This->pTypeInfo) /* can be NULL */ for (pTI = This->pTypeInfo; pTI; pTI = pTINext)
ITypeInfo_Release((ITypeInfo*) This->pTypeInfo); {
pTINext = pTI->next;
ITypeInfo_fnDestroy(pTI);
}
HeapFree(GetProcessHeap(),0,This); HeapFree(GetProcessHeap(),0,This);
return 0; return 0;
} }
...@@ -4887,7 +4892,7 @@ static ITypeInfo2 * ITypeInfo_Constructor(void) ...@@ -4887,7 +4892,7 @@ static ITypeInfo2 * ITypeInfo_Constructor(void)
{ {
pTypeInfoImpl->lpVtbl = &tinfvt; pTypeInfoImpl->lpVtbl = &tinfvt;
pTypeInfoImpl->lpVtblTypeComp = &tcompvt; pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
pTypeInfoImpl->ref=1; pTypeInfoImpl->ref = 0;
pTypeInfoImpl->hreftype = -1; pTypeInfoImpl->hreftype = -1;
pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL; pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL; pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
...@@ -4929,97 +4934,96 @@ static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface) ...@@ -4929,97 +4934,96 @@ static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
ITypeInfoImpl *This = (ITypeInfoImpl *)iface; ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
ULONG ref = InterlockedIncrement(&This->ref); ULONG ref = InterlockedIncrement(&This->ref);
ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
TRACE("(%p)->ref is %u\n",This, ref); TRACE("(%p)->ref is %u\n",This, ref);
if (ref == 1 /* incremented from 0 */)
ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
return ref; return ref;
} }
/* ITypeInfo::Release static void ITypeInfo_fnDestroy(ITypeInfoImpl *This)
*/
static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
{ {
ITypeInfoImpl *This = (ITypeInfoImpl *)iface; TLBFuncDesc *pFInfo, *pFInfoNext;
ULONG ref = InterlockedDecrement(&This->ref); TLBVarDesc *pVInfo, *pVInfoNext;
TLBImplType *pImpl, *pImplNext;
TRACE("(%p)->(%u)\n",This, ref); TRACE("destroying ITypeInfo(%p)\n",This);
if (ref) { SysFreeString(This->Name);
/* We don't release ITypeLib when ref=0 because This->Name = NULL;
it means that function is called by ITypeLib2_Release */
ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
} else {
TLBFuncDesc *pFInfo, *pFInfoNext;
TLBVarDesc *pVInfo, *pVInfoNext;
TLBImplType *pImpl, *pImplNext;
TRACE("destroying ITypeInfo(%p)\n",This); SysFreeString(This->DocString);
This->DocString = NULL;
if (This->no_free_data) SysFreeString(This->DllName);
goto finish_free; This->DllName = NULL;
SysFreeString(This->Name);
This->Name = NULL;
SysFreeString(This->DocString); for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext)
This->DocString = NULL; {
INT i;
for(i = 0;i < pFInfo->funcdesc.cParams; i++)
{
ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i];
if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
{
VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
TLB_Free(elemdesc->u.paramdesc.pparamdescex);
}
SysFreeString(pFInfo->pParamDesc[i].Name);
}
TLB_Free(pFInfo->funcdesc.lprgelemdescParam);
TLB_Free(pFInfo->pParamDesc);
TLB_FreeCustData(pFInfo->pCustData);
if (HIWORD(pFInfo->Entry) != 0 && pFInfo->Entry != (BSTR)-1)
SysFreeString(pFInfo->Entry);
SysFreeString(pFInfo->HelpString);
SysFreeString(pFInfo->Name);
pFInfoNext = pFInfo->next;
TLB_Free(pFInfo);
}
for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext)
{
if (pVInfo->vardesc.varkind == VAR_CONST)
{
VariantClear(pVInfo->vardesc.u.lpvarValue);
TLB_Free(pVInfo->vardesc.u.lpvarValue);
}
TLB_FreeCustData(pVInfo->pCustData);
SysFreeString(pVInfo->Name);
pVInfoNext = pVInfo->next;
TLB_Free(pVInfo);
}
for (pImpl = This->impltypelist; pImpl; pImpl = pImplNext)
{
TLB_FreeCustData(pImpl->pCustData);
pImplNext = pImpl->next;
TLB_Free(pImpl);
}
TLB_FreeCustData(This->pCustData);
SysFreeString(This->DllName); HeapFree(GetProcessHeap(), 0, This);
This->DllName = NULL; }
for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext) /* ITypeInfo::Release
{ */
INT i; static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
for(i = 0;i < pFInfo->funcdesc.cParams; i++) {
{ ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i]; ULONG ref = InterlockedDecrement(&This->ref);
if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
{
VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
TLB_Free(elemdesc->u.paramdesc.pparamdescex);
}
SysFreeString(pFInfo->pParamDesc[i].Name);
}
TLB_Free(pFInfo->funcdesc.lprgelemdescParam);
TLB_Free(pFInfo->pParamDesc);
TLB_FreeCustData(pFInfo->pCustData);
if (HIWORD(pFInfo->Entry) != 0 && pFInfo->Entry != (BSTR)-1)
SysFreeString(pFInfo->Entry);
SysFreeString(pFInfo->HelpString);
SysFreeString(pFInfo->Name);
pFInfoNext = pFInfo->next;
TLB_Free(pFInfo);
}
for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext)
{
if (pVInfo->vardesc.varkind == VAR_CONST)
{
VariantClear(pVInfo->vardesc.u.lpvarValue);
TLB_Free(pVInfo->vardesc.u.lpvarValue);
}
TLB_FreeCustData(pVInfo->pCustData);
SysFreeString(pVInfo->Name);
pVInfoNext = pVInfo->next;
TLB_Free(pVInfo);
}
for(pImpl = This->impltypelist; pImpl; pImpl = pImplNext)
{
TLB_FreeCustData(pImpl->pCustData);
pImplNext = pImpl->next;
TLB_Free(pImpl);
}
TLB_FreeCustData(This->pCustData);
finish_free: TRACE("(%p)->(%u)\n",This, ref);
if (This->next)
{
ITypeInfo_Release((ITypeInfo*)This->next);
}
HeapFree(GetProcessHeap(),0,This); if (!ref)
return 0; {
BOOL not_attached_to_typelib = This->not_attached_to_typelib;
ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
if (not_attached_to_typelib)
HeapFree(GetProcessHeap(), 0, This);
/* otherwise This will be freed when typelib is freed */
} }
return ref; return ref;
} }
...@@ -6654,12 +6658,11 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( ...@@ -6654,12 +6658,11 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
*ppTInfo = (ITypeInfo*) pTypeInfoImpl; *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
/* we use data structures from This, so we need to keep a reference /* the AddRef implicitly adds a reference to the parent typelib, which
* to it to stop it being destroyed and signal to the new instance to * stops the copied data from being destroyed until the new typeinfo's
* refcount goes to zero, but we need to signal to the new instance to
* not free its data structures when it is destroyed */ * not free its data structures when it is destroyed */
pTypeInfoImpl->no_free_data = TRUE; pTypeInfoImpl->not_attached_to_typelib = TRUE;
pTypeInfoImpl->next = This;
ITypeInfo_AddRef((ITypeInfo*) This);
ITypeInfo_AddRef(*ppTInfo); ITypeInfo_AddRef(*ppTInfo);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment