Closed
Bug 469717
Opened 16 years ago
Closed 15 years ago
Crash when using `xf:delete`followed by `xf:send`
Categories
(Core Graveyard :: XForms, defect)
Tracking
(status1.9.2 .9-fixed)
RESOLVED
FIXED
Tracking | Status | |
---|---|---|
status1.9.2 | --- | .9-fixed |
People
(Reporter: jlc6, Assigned: sergeyreym)
References
Details
(Keywords: crash, testcase)
Attachments
(4 files, 4 obsolete files)
1.25 KB,
application/xhtml+xml
|
Details | |
1.15 KB,
application/xml
|
Details | |
1.09 KB,
patch
|
peterv
:
review-
|
Details | Diff | Splinter Review |
2.70 KB,
patch
|
peterv
:
review+
christian
:
approval1.9.2.7-
dveditz
:
approval1.9.2.9+
|
Details | Diff | Splinter Review |
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6pre) Gecko/2008121115 Minefield/3.0.6pre
Build Identifier: CVS trunk
In some cases, when you dispatch an `xf:delete` action followed by an `xf:send` action, Firefox crashes in XPath processing of the binding on the `xf:submission` element that was selected by the `xf:send` action. This happens in both current CVS trunk (as of 2008-12-15) and Firefox 3.0.4 with version 0.8.6ff3 of the Mozilla XForms Extension.
I will post a test case shortly.
Reproducible: Always
Reporter | ||
Comment 1•16 years ago
|
||
This is a simpler test case which also includes an example of delete+send that does work.
Also, if you include an <xf:output ref="deleteme"/> in the page, the "I Do Crash" trigger will work correctly (i.e. not crash).
I had a look into this, but I'm still far away from understanding the tx code, so I couldn't figure out if it's a bug in there or in XForms.
The crash occurs (I think) because the txResultRecycler tries to re-use a node-set that still refers to the deleted node, and thus when it tries to call that txXPathNode's destructor, the code causes a seg fault in nsINode::GetNodeParent.
Sadly, this is as far as I can go until I understand how things work more, so any help would be appreciated.
This sounds familiar. Try this out on FF 3.5 (might need Philipp Wagner to test it for you if you don't build the mercurial tree) and see if it still happens. I seem to remember not pursuing a bug that I suspected was in the xpath code because it was fixed in the current code.
Comment 4•15 years ago
|
||
This bug is different than the one you remember (http://groups.google.com/group/mozilla.dev.tech.xforms/msg/ebc8916cc4ad2d70), and FF 3.5 still crashes.
(In reply to comment #3)
> This sounds familiar. Try this out on FF 3.5 (might need Philipp Wagner to
> test it for you if you don't build the mercurial tree) and see if it still
> happens. I seem to remember not pursuing a bug that I suspected was in the
> xpath code because it was fixed in the current code.
The stack trace for that crash is almost exactly the same, except that instead of nsXFormsModel::ProcessBinds(), it's nsXFormsSubmissionElement::GetBoundInstanceData() that starts off the path to the crash.
Updated•15 years ago
|
Assignee | ||
Comment 6•15 years ago
|
||
Crash appears when txNodeSet clears (in submit action).
I analyzed callgraph and txNodeSet usings. I had thought that error occurs in case of wrong txXPathNode appends to txNodeSet. Thus I had looked at nsXFormsXPathFunctions::Instance. And I removed next code(because this code appends XPath of instance node into txNodeSet):
> if (root) {
> result->Add(root);
> }
It removed instance-function at all. But crashes didn't occur.
So, I was looking then. I had looked at code:
> while (aStart < aEnd) {
> aStart->~txXPathNode();
> ++aStart;
> }
I'm surprized that when Firefox crashes pointers (aStart and aEnd) are equal. How could it be? Why when aStart equals aEnd cycle continues?
Assignee | ||
Comment 7•15 years ago
|
||
I've just forgotten that second code patch is from txNodeSet::destroyElements.
Assignee | ||
Comment 8•15 years ago
|
||
I was cought every call of txXPathNode::txXPathNode(const txXPathNode& aNode) and txXPathNode::~txXPathNode(). And I had seen next error (construcotr is "+", destructor is "-", hex code - is address of Root() that NS_ADDREFS in constructor and NS_RELEASE in destructor):
> +0x7fffdf1ba000
> -0x7fffdf1ba000
> +0x7fffdf1ba000
> +0x7fffdf1ba000
> -0x7fffdf1ba000
Next -0x7fffdf1ba000 crashes Firefox.
Assignee | ||
Comment 9•15 years ago
|
||
I've studied crash. It happens in next reason:
In nsXFormsXPathFunctions::Instance:298 instance node adds to txINodeSet. Also this sets aKeepRootAlive flag.
Next it creates txXPathNode for instance node and in case of aKeepRootAlive (mRefCountRoot) is true constructor does NS_ADDREF(Root()).
Next in nsXFormsInsertDeleteElement::HandleAction:670 makes UnbindFromTree that break parent-child relation.
Next destructor of txINodeSet makes NS_RELEASE(Root()) that crashes Firefox because Root() couldn't process.
Comment 10•15 years ago
|
||
My stack trace is a bit different:
xul.dll!nsINode::GetNodeParent() Line 620 + 0x3 bytes C++
xul.dll!txXPathNode::RootOf(nsINode * aNode=0x050a28f8) Line 104 + 0x8 bytes C++
xul.dll!txXPathNode::Root() Line 111 + 0xb bytes C++
> xul.dll!txXPathNode::~txXPathNode() Line 359 + 0x8 bytes C++
xul.dll!txXPathNode::`scalar deleting destructor'() + 0xf bytes C++
xul.dll!txNodeSet::destroyElements(const txXPathNode * aStart=0x06a156e0, const txXPathNode * aEnd=0x06a156e8) Line 233 C++
xul.dll!txNodeSet::clear() Line 444 + 0x13 bytes C++
xul.dll!txResultRecycler::getNodeSet(txNodeSet * * aResult=0x0012add0) Line 189 C++
xul.dll!LocationStep::evaluate(txIEvalContext * aContext=0x0012ae7c, txAExprResult * * aResult=0x0012ae60) Line 67 + 0x2c bytes C++
xul.dll!PathExpr::evaluate(txIEvalContext * aContext=0x0012af6c, txAExprResult * * aResult=0x0012af64) Line 125 + 0x40 bytes C++
xul.dll!nsXPathExpression::EvaluateWithContext(nsIDOMNode * aContextNode=0x050a261c, unsigned int aContextPosition=0x00000001, unsigned int aContextSize=0x00000001, unsigned short aType=0x0009, nsISupports * aInResult=0x00000000, nsISupports * * aResult=0x0012b2bc) Line 149 + 0x43 bytes C++
xforms.dll!nsXFormsUtils::EvaluateXPath(const nsAString & aExpression={...}, nsIDOMNode * aContextNode=0x050a261c, nsIDOMNode * aResolverNode=0x0509b00c, unsigned short aResultType=0x0009, nsIDOMXPathResult * * aResult=0x0012b484, int aContextPosition=0x00000001, int aContextSize=0x00000001, nsCOMArray<nsIDOMNode> * aSet=0x00000000, nsStringArray * aIndexesUsed=0x00000000) Line 596 + 0x50 bytes C++
xforms.dll!nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement * aElement=0x0509b00c, unsigned int aElementFlags=0x00000000, const nsString_external & aBindingAttr={...}, const nsString_external & aDefaultRef={...}, unsigned short aResultType=0x0009, nsIModelElementPrivate * * aModel=0x0012b4f8, nsIDOMXPathResult * * aResult=0x0012b500, int * aUsesModelBind=0x0012b504, nsIXFormsControl * * aParentControl=0x00000000, nsCOMArray<nsIDOMNode> * aDeps=0x00000000, nsStringArray * aIndexesUsed=0x00000000) Line 788 + 0x46 bytes C++
xforms.dll!nsXFormsSubmissionElement::GetBoundInstanceData(nsIDOMNode * * result=0x0012b604) Line 1105 + 0x6a bytes C++
xforms.dll!nsXFormsSubmissionElement::Submit() Line 757 + 0x26 bytes C++
Comment 11•15 years ago
|
||
So it looks like nsINode::GetNodeParent() crashes, also the nsINode object is in bad shape since it hasn't node info, mParentPtrBits cannot be evaluated in debugger.
I think txXPathNode makes bad things when it addrefs and releases the result of Root() computations. Since the parent chain of the mNode can be changed then Root() might fail when it tries to release the object what should lead to crash.
Comment 12•15 years ago
|
||
cc'ing Peter and Jonas.
Comment 13•15 years ago
|
||
Our XPath engine has never been able to deal with changes to the DOM while an XPath expression is being evaluated, it assumes a static DOM.
Comment 14•15 years ago
|
||
That's was an assumption, possibly wrong. Peter, could you please try the testcase? (however you will need to build firefox with xforms and schema-validation extensions).
Comment 15•15 years ago
|
||
It'll be a while before I can try that out. Comment 9 seems to imply that nsXFormsInsertDeleteElement::HandleAction is called during XPath evaluation?
Assignee | ||
Comment 16•15 years ago
|
||
(In reply to comment #15)
> It'll be a while before I can try that out. Comment 9 seems to imply that
> nsXFormsInsertDeleteElement::HandleAction is called during XPath evaluation?
No, XPath evaluation is in HandleAction.
Comment 17•15 years ago
|
||
What I get from what you are saying in comment 8 and 9 is that when the NS_RELEASE(Root()) happens that crashes, it still has a refcount of 1, right? Which means that it shouldn't crash because according to the refcount, the object should still be alive. But if it is not, you should look into why that is. For example, at what point does the data in the object go bad/get overwritten? It must be some time between the last NS_RELEASE that crashes and the one before that which had no problem, right?
Assignee | ||
Comment 18•15 years ago
|
||
As I wrote that problem is that HandleAction destroy node is root of nodes which will destroy later.
Simple solution of this is make don't adding refs and release of Root() of instance.
I did this patch to certain of problem above.
May be this patch is normal because I don't know for what txNodeSetAdaptor::Add creates txXPathNativeNode with aKeepRootAlive flag.
Assignee | ||
Comment 19•15 years ago
|
||
Why node creates with aKeepRootAlive == true in this:
txNodeSetAdaptor::Add(nsIDOMNode *aNode) {
NS_ENSURE_TRUE(mWritable, NS_ERROR_FAILURE);
nsAutoPtr<txXPathNode> node(txXPathNativeNode::createXPathNode(aNode, PR_TRUE));
And how I could make adding of node to txNodeSetAdaptor with no aKeepRootAlive?
Comment 20•15 years ago
|
||
(In reply to comment #19)
> Why node creates with aKeepRootAlive == true in this:
Because we need to keep ancestors alive. Holding a node alive without holding the root of the subtree that that node is in will cause dangling parent pointers and crashes.
> And how I could make adding of node to txNodeSetAdaptor with no aKeepRootAlive?
You shouldn't, you should not disconnect the root from the node while the txNodeSetAdaptor is alive. Or if you do, you should addref the new root and release the old one.
Comment 21•15 years ago
|
||
(In reply to comment #9)
> Next destructor of txINodeSet makes NS_RELEASE(Root()) that crashes Firefox
> because Root() couldn't process.
When does this destructor run? The XPathResult doesn't keep the txNodeSet alive specifically for this reason, so why is it alive while nsXFormsInsertDeleteElement::HandleAction removes the node from its parent?
Assignee | ||
Comment 22•15 years ago
|
||
Callstack looks like this:
> RootExpr::evaluate
> txResultRecycler::getNodeSet
> txNodeSet::clear
> txNodeSet::destoyElements
> ~txXPathNode
> txXPathNode::RootOf
> <and there is crash>
Assignee | ||
Comment 23•15 years ago
|
||
Another note about bug. I've found that creating of txXPathNode and it's destoying in txNodeSet) occurs in RootExpr::evaluate.
> txXPathTreeWalker walker(aContext->getContextNode()); -- there is a creating
> walker.moveToRoot();
> return aContext->recycler()->getNodeSet(walker.getCurrentPosition(), aResult); -- there is a destroying
walker.moveToRoot() is not cause of crash.
Assignee | ||
Comment 24•15 years ago
|
||
In tx nodes add to the nodeset that stores in txResultRecycler object. So nodeset from InsertDeleteElement::HandleAction moves to Submit via txResultRecycler (same txResultRecycler object that in HandleAction and Submit). In submit nodeset tries to clear itself and firefox crashes because one parent node of node from nodeset already has been destroyed in InsertDeleteElement::HandleAction.
Could I make to clear recycler in InsertDeleteElement?
Assignee | ||
Comment 25•15 years ago
|
||
Why I can't do somethink like this in InsertDeleteElement ?:
> nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(nodeset);
> xpathResult->recycler();
I have errors that no nsIXPathResult. How could I connect such headers and is it possible?
Comment 26•15 years ago
|
||
Hi Sergey, I think that you are looking at this from the wrong angle. You seem to be trying to avoid the crash from the XForms point of view. The recycler is internal to XPath. I doubt that it should be acted on directly by an outside user like XForms.
If I've been following this thread correctly, somehow this root is being freed before it has a zero reference count, right? And that when it finally does have a zero reference count and goes through the destructor like it is supposed to, it crashes because it has already been freed. This should never happen for a xpcom object. So I think tracking down why it is freed before its reference count is zero is the way to go.
Assignee | ||
Comment 27•15 years ago
|
||
I just add refs to removed node. And I think that then recycler release this node and destructor process it.
And is it normal that handling of insert and delete node in same class? It's done by next code in handling:
> if (mIsInsert) {
> ...
> } else {
> ...
> }
Attachment #431832 -
Flags: review?(surkov.alexander)
Assignee | ||
Updated•15 years ago
|
Attachment #431832 -
Flags: review?(surkov.alexander) → review?(aaronr)
Comment 28•15 years ago
|
||
Comment on attachment 431832 [details] [diff] [review]
patch
> rv = parentNode->RemoveChild(locationNode, getter_AddRefs(resNode));
>+ NS_ADDREF(resNode);
It must be a leak.
Assignee | ||
Comment 29•15 years ago
|
||
Simple calls-tracing of txXPathNode() and ~txXPathNode() show that this node normally destroying in txNodeSet::clear()
Comment 30•15 years ago
|
||
(In reply to comment #29)
> Simple calls-tracing of txXPathNode() and ~txXPathNode() show that this node
> normally destroying in txNodeSet::clear()
For all possible cases? For example, I'm a bit sceptic because of line
NS_ENSURE_SUCCESS(rv, rv);
if it fails then will it destroyed as well?
Also it would be nice to have some portion of comments, at least it's not evident why it doesn't leak.
Assignee | ||
Comment 31•15 years ago
|
||
I put comments.
Attachment #431832 -
Attachment is obsolete: true
Attachment #431860 -
Flags: review?(surkov.alexander)
Attachment #431832 -
Flags: review?(aaronr)
Comment 32•15 years ago
|
||
Comment on attachment 431860 [details] [diff] [review]
patch 2
I'm not sure this way is exactly what Aaron suggested, so it's better to get his first review.
Actually it looks unsafe to addref in XForms module and except it will be released outside of XForms because the proposed way is not standard convention of addref/release.
Attachment #431860 -
Flags: review?(surkov.alexander)
Assignee | ||
Updated•15 years ago
|
Attachment #431860 -
Flags: review?(aaronr)
Comment 33•15 years ago
|
||
Comment on attachment 431860 [details] [diff] [review]
patch 2
But what happens in all the cases that DON'T crash firefox? Does that mean that in those cases we'll be leaking this node? Remember, we only seem to be crashing when instance() is used which is certainly not all of the cases.
Assignee | ||
Comment 34•15 years ago
|
||
(In reply to comment #33)
> (From update of attachment 431860 [details] [diff] [review])
> But what happens in all the cases that DON'T crash firefox? Does that mean
> that in those cases we'll be leaking this node? Remember, we only seem to be
> crashing when instance() is used which is certainly not all of the cases.
When node removes it stay in nodeset. Nodeset lives from nsXFormsInsertDeleteElement::HandleAction to nsXFormsSubmitElement::HandleAction or any other that uses tx. Destructor for node calls in InsertDeleteElement because reference count is zero but node is still alive in nodeset. So I think that this is normal solution to addref because node is still alive.
It could make memory leak 'til next txNodeset using.
Bug appears due to using of instance() makes nodes adding to nodeset with addrefing root of them. If no instance() function then nodes adding don't add refs to roots of nodes.
Comment 35•15 years ago
|
||
Feel free to run this by Olli (whose xpcom isn't nearly as rusty as mine), but I don't think that addref'ing here is the right solution. If the reference count for the node should be > 0 after the delete because it still lives in a xpath structure, then it should have been > 1 before we deleted it. Doing an addref here might get us around a crash, but I think it would just be hiding whatever the real problem is. But again, ask Olli's opinion.
Comment 36•15 years ago
|
||
If you add an NS_ADDREF, you need to add also NS_RELEASE somewhere.
Comment 37•15 years ago
|
||
...otherwise you leak.
XPCOM_MEM_LEAK_LOG=1 environment variable is useful for detecting memory leaks.
Set the variable, start browser, do something which may leak, wait a bit
so that cycle collector runs (15 seconds or so doing *nothing*) and close the
browser. If there are leaks, those should be reported in the console.
You may need to re-do the same steps to make sure the leak is really
reproducable.
Comment 38•15 years ago
|
||
Yeah, the NS_ADDREF is definitely wrong. The right solution is probably to make txResultRecycler::recycle call clear() on mNodeSetResults before pushing it to mNodeSetResults. Does that work?
Updated•15 years ago
|
Attachment #431860 -
Flags: review?(aaronr) → review-
Comment 39•15 years ago
|
||
(In reply to comment #38)
> call clear() on mNodeSetResults
Er, make that "call clear() on static_cast<txNodeSet*>(aResult)"
Assignee | ||
Comment 40•15 years ago
|
||
(In reply to comment #39)
> (In reply to comment #38)
> > call clear() on mNodeSetResults
>
> Er, make that "call clear() on static_cast<txNodeSet*>(aResult)"
This midification solve FF crashes problem. But I don't think that tx modification can be possible.
Assignee | ||
Comment 41•15 years ago
|
||
Attachment #427137 -
Attachment is obsolete: true
Attachment #433537 -
Flags: review?(peterv)
Comment 42•15 years ago
|
||
Comment on attachment 433537 [details] [diff] [review]
tx patch
> void
> txResultRecycler::recycle(txAExprResult* aResult)
> {
>+ static_cast<txNodeSet*>(aResult)->clear();
This is wrong, at this point you could have a non-nodeset aResult. This needs to only happen in the nodeset case.
It also doesn't remove the clear calls from all the getNodeSet implementations that aren't needed anymore.
(In reply to comment #40)
> But I don't think that tx
> modification can be possible.
I have no idea what that means.
Attachment #433537 -
Flags: review?(peterv) → review-
Assignee | ||
Comment 43•15 years ago
|
||
Attachment #433537 -
Attachment is obsolete: true
Attachment #433547 -
Flags: review?(peterv)
Comment 44•15 years ago
|
||
Comment on attachment 433547 [details] [diff] [review]
tx patch
See comment 42. BTW, I didn't say anything about checking for isEmpty, it's unnecessary.
Attachment #433547 -
Flags: review?(peterv) → review-
Assignee | ||
Comment 45•15 years ago
|
||
Remove clear calls from getNodeset and remove isEmpty.
Attachment #433547 -
Attachment is obsolete: true
Attachment #433887 -
Flags: review?(peterv)
Assignee | ||
Comment 46•15 years ago
|
||
Peter, can you look at this again?
Updated•15 years ago
|
Attachment #433887 -
Flags: review?(peterv) → review+
Assignee | ||
Comment 47•15 years ago
|
||
Peter, who could be co-reviwer in that patch?
Comment 48•15 years ago
|
||
No one, this patch is good to go. Get someone to check it in (set checkin-needed keyword if necessary).
Updated•15 years ago
|
Keywords: checkin-needed
Updated•15 years ago
|
Assignee: nobody → sergeyreym
Comment 49•15 years ago
|
||
Comment 50•15 years ago
|
||
landed on 1.9.3 - http://hg.mozilla.org/mozilla-central/rev/aba6af3a5ad1
Assignee | ||
Comment 51•15 years ago
|
||
Comment on attachment 433887 [details] [diff] [review]
tx patch
That patch in 1.9.2 need for fix crash that appears in XForms. It would be nice to fix that bug in nearest release of XForms. I developed this patch in 1.9.2 and test it. Also this patch makes safe changes because nodeset::clear() calls move to another (in callstack) methods (getNodeSet).
Attachment #433887 -
Flags: approval1.9.2.5?
Assignee | ||
Comment 52•15 years ago
|
||
Hmmm. I mean:
It would be nice to fix that bug in nearest release of Firefox.
Comment 53•15 years ago
|
||
I'd rather not wait since there is no guarantee this will be approved. We can always refresh the xforms release with this patch included if it does get approved. What does everyone else think?
Comment 54•15 years ago
|
||
Yes, I guess the new XForms addon 0.8.7 is already in the AMO review queue (if Doron uploaded it). We can always do a stability release if necessary.
Assignee | ||
Updated•14 years ago
|
Attachment #433887 -
Flags: approval1.9.2.6?
Updated•14 years ago
|
Attachment #433887 -
Flags: approval1.9.2.5?
Comment 55•14 years ago
|
||
Comment on attachment 433887 [details] [diff] [review]
tx patch
We won't be taking this in 1.9.2.6...we already have too many fixes and a tight schedule. Feel free to nominate it for .7 though
Attachment #433887 -
Flags: approval1.9.2.6? → approval1.9.2.6-
Assignee | ||
Updated•14 years ago
|
Attachment #433887 -
Flags: approval1.9.2.7?
Comment 56•14 years ago
|
||
Comment on attachment 433887 [details] [diff] [review]
tx patch
Approved for 1.9.2.9, a=dveditz for release-drivers
Attachment #433887 -
Flags: approval1.9.2.9? → approval1.9.2.9+
Comment 57•14 years ago
|
||
status1.9.2:
--- → .9-fixed
Updated•8 years ago
|
Product: Core → Core Graveyard
You need to log in
before you can comment on or make changes to this bug.
Description
•