msxml3: Refcount the domdoc/xmldoc properties.

Multiple domdoc and xmlDoc objects may need to share a common
properties object but may be released independently. So add a
reference count on the properties object.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43377
Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Francois Gouget 2021-05-06 18:08:06 +03:00 committed by Alexandre Julliard
parent 54459e593f
commit 0e87427500
1 changed files with 41 additions and 6 deletions

View File

@ -80,6 +80,7 @@ static const WCHAR PropertyNormalizeAttributeValuesW[] = {'N','o','r','m','a','l
* We need to preserve this when reloading a document, * We need to preserve this when reloading a document,
* and also need access to it from the libxml backend. */ * and also need access to it from the libxml backend. */
typedef struct { typedef struct {
LONG refs;
MSXML_VERSION version; MSXML_VERSION version;
VARIANT_BOOL preserving; VARIANT_BOOL preserving;
IXMLDOMSchemaCollection2* schemaCache; IXMLDOMSchemaCollection2* schemaCache;
@ -290,6 +291,7 @@ static domdoc_properties *create_properties(MSXML_VERSION version)
{ {
domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties)); domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
properties->refs = 1;
list_init(&properties->selectNsList); list_init(&properties->selectNsList);
properties->preserving = VARIANT_FALSE; properties->preserving = VARIANT_FALSE;
properties->schemaCache = NULL; properties->schemaCache = NULL;
@ -316,6 +318,7 @@ static domdoc_properties* copy_properties(domdoc_properties const* properties)
if (pcopy) if (pcopy)
{ {
pcopy->refs = 1;
pcopy->version = properties->version; pcopy->version = properties->version;
pcopy->preserving = properties->preserving; pcopy->preserving = properties->preserving;
pcopy->schemaCache = properties->schemaCache; pcopy->schemaCache = properties->schemaCache;
@ -345,9 +348,31 @@ static domdoc_properties* copy_properties(domdoc_properties const* properties)
return pcopy; return pcopy;
} }
static void free_properties(domdoc_properties* properties) static domdoc_properties * properties_add_ref(domdoc_properties *properties)
{ {
if (properties) LONG ref;
if (!properties) return NULL;
ref = InterlockedIncrement(&properties->refs);
TRACE("%p, %d.\n", properties, ref);
return properties;
}
static void properties_release(domdoc_properties *properties)
{
LONG ref;
if (!properties) return;
ref = InterlockedDecrement(&properties->refs);
TRACE("%p, %d.\n", properties, ref);
if (ref < 0)
WARN("negative refcount, expect troubles\n");
if (ref == 0)
{ {
if (properties->schemaCache) if (properties->schemaCache)
IXMLDOMSchemaCollection2_Release(properties->schemaCache); IXMLDOMSchemaCollection2_Release(properties->schemaCache);
@ -622,7 +647,7 @@ LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
xmlFreeNode( orphan->node ); xmlFreeNode( orphan->node );
heap_free( orphan ); heap_free( orphan );
} }
free_properties(priv->properties); properties_release(priv->properties);
heap_free(doc->_private); heap_free(doc->_private);
xmlFreeDoc(doc); xmlFreeDoc(doc);
@ -679,10 +704,16 @@ static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
if(This->node.node) if(This->node.node)
{ {
properties_release(properties_from_xmlDocPtr(get_doc(This)));
priv_from_xmlDocPtr(get_doc(This))->properties = NULL; priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
if (xmldoc_release(get_doc(This)) != 0) if (xmldoc_release(get_doc(This)) != 0)
{
/* The xmlDocPtr object can no longer use the properties of this
* domdoc object. So give it its own copy.
*/
priv_from_xmlDocPtr(get_doc(This))->properties = priv_from_xmlDocPtr(get_doc(This))->properties =
copy_properties(This->properties); copy_properties(This->properties);
}
} }
This->node.node = (xmlNodePtr) xml; This->node.node = (xmlNodePtr) xml;
@ -690,7 +721,10 @@ static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
if(This->node.node) if(This->node.node)
{ {
xmldoc_add_ref(get_doc(This)); xmldoc_add_ref(get_doc(This));
priv_from_xmlDocPtr(get_doc(This))->properties = This->properties; /* Only attach new xmlDocPtr objects, i.e. ones for which properties
* is still NULL.
*/
priv_from_xmlDocPtr(get_doc(This))->properties = properties_add_ref(This->properties);
} }
return S_OK; return S_OK;
@ -975,6 +1009,7 @@ static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
for (eid = 0; eid < EVENTID_LAST; eid++) for (eid = 0; eid < EVENTID_LAST; eid++)
if (This->events[eid]) IDispatch_Release(This->events[eid]); if (This->events[eid]) IDispatch_Release(This->events[eid]);
properties_release(This->properties);
release_namespaces(This); release_namespaces(This);
heap_free(This); heap_free(This);
} }
@ -3675,7 +3710,7 @@ HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
doc->async = VARIANT_TRUE; doc->async = VARIANT_TRUE;
doc->validating = 0; doc->validating = 0;
doc->resolving = 0; doc->resolving = 0;
doc->properties = properties_from_xmlDocPtr(xmldoc); doc->properties = properties_add_ref(properties_from_xmlDocPtr(xmldoc));
doc->error = S_OK; doc->error = S_OK;
doc->site = NULL; doc->site = NULL;
doc->base_uri = NULL; doc->base_uri = NULL;
@ -3714,7 +3749,7 @@ HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj); hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
if(FAILED(hr)) if(FAILED(hr))
{ {
free_properties(properties_from_xmlDocPtr(xmldoc)); properties_release(properties_from_xmlDocPtr(xmldoc));
heap_free(xmldoc->_private); heap_free(xmldoc->_private);
xmlFreeDoc(xmldoc); xmlFreeDoc(xmldoc);
return hr; return hr;