Crash when XmlElement is destroyed after writing to stream

I am porting a plug-in from JUCE 5.3.2 to 5.4.7, and am getting a crash in getStateInformation(), when my XmlElement (that I am using to stream data to the session chunk via copyXmlToBinary()) goes out of scope.

Previously, I used a ScopedPointer to create the XmlElement, but that caused a crash. So I changed to just using an XmlElement object directly (since it no longer seemed apparent why I used a pointer in the first place for this), but it also crashes when going out of scope.

I do not delete any of the children of the XmlElement myself, so I’m confused as to why it is crashing now, but did not under Juce 5.3.2. Any thoughts? What changed about how to write chunk data using an XmlElement and copyXmlToBinary()?

I wonder if it has something to do with how I am getting the xml into one of the child XmlElements? Here is a function I have that adds the parameter data to my larger XmlElement. I modified the code from the original because createXml now returns a std::unique_ptr, which I am not very familiar with using. I suspect I did something wrong here:

void MyPluginAudioProcessor::writeParametersChunkData( XmlElement* pParametersXml )
{
auto state = parameters.copyState();
	// ORIGINAL WAS THIS: XmlElement* pParameterTreeXml(state.createXml());
	std::unique_ptr<XmlElement> pParameterTreeXml = state.createXml();
	pParametersXml->addChildElement(pParameterTreeXml.get()); // ADDED .get() HERE
}

Hey Howard.

I just took a quick look at the underlying data structure of the XML object. It looks like it’s using a linked list, and likely taking ownership of that pointer. You’re storing the pointer in an std::unique_ptr.

Likely it’s crashing when the unique_ptr goes out of scope.

I’m not 100% but I’d check on the ownership of that pointer you’re passing in and be sure addChildElement doesn’t take ownership of the pointer, otherwise you should just pass the new raw pointer in and let the XMLElement* manage the ownership

Ahh yeah here we go:

/** Appends an element to this element's list of children.

    Child elements are deleted automatically when their parent is deleted, so
    make sure the object that you pass in will not be deleted by anything else,
    and make sure it's not already the child of another element.

    Note that due to the XmlElement using a singly-linked-list, prependChildElement()
    is an O(1) operation, but addChildElement() is an O(N) operation - so if
    you're adding large number of elements, you may prefer to do so in reverse order!

    @see getFirstChildElement, getNextElement, getNumChildElements,
         getChildElement, removeChildElement
*/
void addChildElement (XmlElement* newChildElement) noexcept;

The important bit:

    Child elements are deleted automatically when their parent is deleted, so
    make sure the object that you pass in will not be deleted by anything else,
    and make sure it's not already the child of another element.

try:

pParametersXml->addChildElement(pParameterTreeXml.release());
2 Likes

That looks like it does the trick. Thanks so much! Like I said, I’m not too familiar with using std::unique_ptr. So I guess when it went out of scope here, it was deleting the data. That explains why in my tracing back through the call stack, I didn’t see any actual data inside that node after exiting the function!

1 Like

No prob, big love for Antares!

1 Like