Forums » Saxon/C Help and Discussions »
Returned object deletion
Added by Paul Greve 19 days ago
Hi. We use SaxonC to parse XML instance docs along with doing xpath queries using the parsed XdmNode *. Is there any documentation or rule of thumb on what if any objects returned by SaxonC need to be deleted?
Does deleting the XdmNode * returned by the SaxonProcessor parse functions delete all the "child" objects that it references? Do all objects (pointers) returned by XdmNode function calls need to be deleted?
Does deleting the XdmValue * returned by the XPathProcessor evaluate function delete all the "child" objects that it references? Do all objects (pointers) returned by XdmValue function calls need to be deleted?
Replies (16)
Please register to reply
RE: Returned object deletion - Added by O'Neil Delpratt 18 days ago
Hi Paul,
Thanks for your post on this topic. I have created the following bug issue: #6623 to provide better documentation on memory management.
In answer to your question it is the users responsibility to delete the XdmNode * returned by SaxonProcessor
parse functions. The same can be said for XdmValue
* returned by XPathProcessor.evaluate
. Similarly, XdmValue objects returned by method in XsltExecutable and in XQueryProcessor.
When you say child object pointers: The child objects are lazily created. Therefore when these methods are called: getChildren()
, axisNodes
, getChild
and getAttributeNodes
you will get one or more XdmNode objects created. You only have to delete the pointers created.
For example:
int childCountA = node->getChildCount();
XdmNode **children = node->getChildren();
for (int i = 0; i < childCount; i++) {
const char *childStr = children[i]->toString();
cout << "child node:" << (childStr) << endl;
operator delete((char *)childStr);
}
for (int i = 0; i < childCount; i++) {
delete children[i];
}
delete[] children;
...
delete node;
It is the same for the XdmValue. The items are lazily created. When you retrieve an XdmItem * using itemAt
or getHead
the caller is responsible for deallocating memory of the pointer to XdmItem.
Example:
XdmValue *resultValues = xpath->evaluate("//person");
if (resultValues != nullptr) {
XdmItem *itemi = resultValues->itemAt(2);
...
const char *itemiStr = itemi->getStringValue();
cout << "Item at " << i << " =" << itemiStr << endl;
operator delete((char *)itemiStr);
delete itemi;
}
Notice for the access of string values we use operator delete
on the char *. This is because internally we use operator new
for the string allocation created in the Java code.
I am happy to help if you have any further questions.
RE: Returned object deletion - Added by Paul Greve 18 days ago
Thanks for the info O'Neill. This is very helpful.
RE: Returned object deletion - Added by Paul Greve 18 days ago
Hi O'Neill. I took you info and updated my code accordingly. One problem/question though, I'm calling 'operator delete()' for all returned strings; but I'm getting a 'double free or corruption' error when deleting a string returned from a call to XdmNode::getAttributeValue(const char *name). Is the deletion not needed for all returned strings?
RE: Returned object deletion - Added by O'Neil Delpratt 18 days ago
It is unclear to me why the XdmNode::getAttributeValue
method would give you a double free
. I suspect the cause is another string method. Can you send me a repo please?
RE: Returned object deletion - Added by O'Neil Delpratt 18 days ago
Just to mention there are are few places where the strings are handled internally. These are for string that are usually small and can be accessed many times, for example getNodeName() (See documentation: https://www.saxonica.com/saxon-c/doc12/html/classXdmNode.html#a23f3f05832564696a6a6c94bf0ac9d9e) and getLocalName
.
On the other hand the larger string coming from the method getStringValue we don't cache the string therefore deallocation of memory is on the user.
RE: Returned object deletion - Added by Paul Greve 18 days ago
Hi O'Neill. Thanks for pointing out the documentation on XdmNode::getLocalName() and getNodeName(). I was calling 'operator delete()' for those too but hadn't gotten to them in my testing yet. I'll put together a standalone example of the double free error that I'm getting with XdmNode::getAttributeValue() to see if I still get the error and I'll post it.
RE: Returned object deletion - Added by Paul Greve 17 days ago
Hi O'Neill,
I'm experiencing 4 different problems with deleting objects. The attached program demonstrates all 4. The first is that deleting the object returned by XdmNode::getAttributeValue() gives a double free error. The other three all have to do with the fact that we have the need to pass individual nodes (XdmNode *) around to different parts of our application and I'm trying to find the best way to do that to include deleting those objects. The issues are all marked with ISSUE # in the code. Any help would be greatly appreciated.
Paul
SaxonDeleteTest.cpp (7.51 KB) SaxonDeleteTest.cpp |
RE: Returned object deletion - Added by O'Neil Delpratt 16 days ago
Hi Paul,
Thanks for providing the code. Just checking are you running against SaxonC 12.5? Also on which platform?
I ran the code on macOS M3 chip and it ran to the end without seg faulting.
RE: Returned object deletion - Added by Paul Greve 15 days ago
Hi O'Neill.
Our final target platform is the 64-bit ARM running linux; but I haven't tested on that platform yet. I'm unit testing on the x86_64 using CentOS9. That's where I'm seeing the issues with code I posted. The different issues are commented out with #if 0's. You can't see them all in a single run. I'm using SaxonC 12.2 which I realize isn't the latest. Let see if I can get the latest and I'll let you know if that helps.
Paul
RE: Returned object deletion - Added by O'Neil Delpratt 15 days ago
Please try running SaxonC 12.5 if possible. There has been a lot of work in the area of memory management since 12.2.
RE: Returned object deletion - Added by O'Neil Delpratt 15 days ago
I confirm I reproduce the segmentation errors on SaxonC 12.2 . Moving forward to the latest release will resolve your issues.
RE: Returned object deletion - Added by Paul Greve 15 days ago
Hi O'Neill,
I was able to get the latest release (12.5) downloaded and integrated with the posted sample test program. All my issues memory management disappeared.
I apologize for not trying the latest release before raising a red flag. It dawned on me right after posting the program.
One last thing if you don't mind. Like I mentioned this all stems from our need to pass individual nodes around; so I was looking for the best solutions for that and trying different things.
To that end, the sample program offers two ways to get the root element, getRoot() and getElement(). Each of those offers the further option of using the original node or making a copy of it.
For 3 of the 4 combinations, subsequent calls to XdmNode::getChildren() return a valid pointer. However, when you make a copy of the XdmNode in getRoot(), the subsequent call to XdmNode::getChildren() (in printChildren()) returns a nullptr.
That makes sense if the copy constructor for XdmNode doesn't do a deep copy. However, what doesn't make sense is that if you make a copy of the XdmNode (XdmItem returned by xpath query) in getElement(), the subsequent call to XdmNode::getChildren() returns a valid pointer.
I would think those two copies are doing the same thing. Any ideas on what I might be missing here would be greatly appreciated.
Paul
RE: Returned object deletion - Added by O'Neil Delpratt 15 days ago
Hi Paul,
Glad to know most of the issues are now resolved. Thanks for highlighting the issue with the copy constructor. I managed to reproduce the same problem you mentioned. This is a bug. The getChildren()
method should return a valid pointer. I did notice some another issue with the copy constructor for other Xdm types, so this looks familiar. I will create a new bug issue to track this problem.
RE: Returned object deletion - Added by O'Neil Delpratt 14 days ago
Hi Paul,
I have created the following bug issue #6628 to track the copy constructor problem. I will work on a fix for this, which will be available in the next maintenance release. As mentioned in the bug issue my advice is to avoid using the copy constructor. Both getRoot()
and getElement()
should give you a valid pointer. I think getElement()
is working properly by accident, but the problem is still there. Maybe the GC is not being triggered in this path.
RE: Returned object deletion - Added by Paul Greve 14 days ago
Yea. That was my plan based on this exercise. Thanks O'Neill.
Please register to reply