Open
Bug 138183
Opened 22 years ago
Updated 2 years ago
Improve handling of recursive template invocation
Categories
(Core :: XSLT, enhancement)
Core
XSLT
Tracking
()
NEW
Future
People
(Reporter: axel, Unassigned)
References
(Blocks 1 open bug, )
Details
Attachments
(1 obsolete file)
XSLT has the ability of circular references thru <xsl:apply-templates select="some reference to non-child nodes" />. We might not get all, but we might wanna catch at least obvious ones like select="." without changing the mode. As the spec doesn't require this, it's just an enhancement.
The only (non-insane-complicated) way i can think of to fully fix this is to count the template-recursion-depth and stop at, say, 500. Should be pretty easy to hook into XSLTProcessor::processTemplate. We can't just catch select="." in apply-templates since that can be legal, for example: <template match="foo"> <param name="value" select="500"/> <if test="$value > 500"> <apply-templates select="."/> </if> <if test="$value <= 500 and $value > 0"> <value-of select="$value"/> <apply-templates select="."> <with-param select="$value - 1"/> </apply-templates> </if> </template> counts from param "value" (limited and defaulted to 500) down to 1
Reporter | ||
Comment 2•22 years ago
|
||
I don't think we should vaguely catch all recursions, but instead just catch easy-to-detect short loops. At least in the first pass. Those are: <xsl:apply-templates /> and <xsl:call-template /> could check if xslTemplate is the current template and if (actualParams->isEmpty()) in XSLTProcessor::processAction if we add the template to the TemplateRule This one is indeed pretty easy, huh? And should catch at least the typos or easy to solve stylesheet errors. Everything that goes further would require us to hold a stack, and presumably on every Nth run check the stack for the current template and compare the variable bindings. I don't feel too good about such a thing, I'm afraid it'll get costly.
Blocks: 112622
> I don't think we should vaguely catch all recursions, but instead just
> catch easy-to-detect short loops. At least in the first pass.
> Those are:
> <xsl:apply-templates /> and <xsl:call-template /> could check if
> xslTemplate is the current template and if (actualParams->isEmpty()) in
> XSLTProcessor::processAction if we add the template to the TemplateRule
Nope, that will not work. Calling the current template without providing any
parameters is legal as shown in my example.
What we can catch is if apply-templates/call-template invoces the current
template *and* the current template is without parameters *and* the
apply-templates/call-template doesn't have any with-param.
However I think it would be easier to just do
if (aPs->mTemplateRecursionLevel++ > 500) {
// report error
return;
}
// execute template
aPs->mTemplateRecursionLevel--;
in XSLTProcessor::processTemplate
(we could wrap the member in add/decrease functions)
Reporter | ||
Comment 4•22 years ago
|
||
I don't like the counting approach. Basically, because it's not an error. If we had a way to ask the user, I'd be fine with that. But I don't see that on the horizon. Though I bet I'm not the only one who would like to keep the UI responsive during transforms (which is the base to display a dialog, right?) Can we inspect the parameters of this template instantiation and the previous? And bail if the parameters didn't change?
If we don't do the counting approch we have to do some serious rearchitecturing to compleatly avoid crashes. Even if we did check for same-template-same-parameters all the way up the "template recursion stack" we would still crash for something like: <template name="foo"> <param name="val" select="1"/> <call-template name="foo"> <with-param name="val" select="$val + 1"/> </call-template> </template> I don't like the counting way either since it can make perfectly valid stylesheets fail, however i can't see any other not-insane-complicated way. The insane-complicated way would be to make all the processXXX functions non- recursive and manually build stacks with everything we need. I think that this is what the js-engine does to prevent crashes for things like function a() { return b(); } function b() { return a(); }
the insane-complicated way might be worth looking into when we start compiling the stylesheets...
*** Bug 163476 has been marked as a duplicate of this bug. ***
fwiw, IE stops at template-depth 16383 where xsl:for-each counts as template (nice round number 'ey :-) )
Comment 9•22 years ago
|
||
Regarding #4. You could: - stop processing at 500th recursion level; - render what you got so far; - display dialog stating "Processing of XML document was not finished due to very deep recursion. If you choose to reprocess with deeper recursion <red>YOU COULD CRASH</red> your browser!", and two buttons: <<CANCEL>> (default) and <Reprocess with deeper recursion>. - If user chooses to reprocess - "are you sure?" dialog could be helpfull.
Comment 10•22 years ago
|
||
Demo, how to catch stack overflow. Limitations: 1) does not take into account systems where stack grows in other direction than Linux/x86; 2) does not take into account threads, but with litle help of thread creating code that should be possible;
Reporter | ||
Comment 11•22 years ago
|
||
Comment on attachment 97151 [details]
stack overflow catch demo
This looks completely unportable, and is pretty off-topic
Attachment #97151 -
Attachment is obsolete: true
Attachment #97151 -
Attachment mime type: application/octet-stream → text/plain
Comment 12•22 years ago
|
||
re, off-topic. #163476 is duplicate of this bug. And comment #8 by Jonas Sickings reads <...>unfortunatly I don't know of any way to check for out-of-stackspace.<...> re, portability. This demo is not supposed to demonstrate how to learn how much of stack space we are given. It is supposed to demonstrate check _if we are running out of it_. And this could be minimized to check of relation of address of local variable to some long number. Yes, relation (< or >) depends on how stack on that platform grows. But this is the same platform dependency as is endianness or the way how to put button in the window. Both latter problems are solved by making API which hides gorry details. I am sure, this could be done to this problem also.
Comment 13•22 years ago
|
||
*** Bug 180321 has been marked as a duplicate of this bug. ***
Depends on: xslt_compile
I thought about this bug in the post-compilation world. Even though we in theory could run the transformation until we run out of memory and then bail I don't think we really want to do that. First of all we would most likly end up thrasing harddrive for quite a while before actually running out of memory. Second eating up all the heapmemory will probably crash mozilla (no matter how hard we try not to crash on OOM i doubt that we actually won't crash) as well as unstablaize ever other app running on the clients computer since they will run low on memory too. So I think we need to put a cap on the level of recursiondepth even in the new world. The number could probably be higher now that we're eating heap rather then stack though. MS uses a cap of 16383 and i think we could have a number as high up there, say 20000?
*** Bug 196447 has been marked as a duplicate of this bug. ***
Reporter | ||
Comment 16•21 years ago
|
||
The depth limit of 20k has landed. I still think we should investigate something more friendly, and in cases of just wrong selects, more responsive. Any means to check for recursion beyond what we have now might end up with a performance toll, though, so I vote for keeping this open and evaluate which schema costs what once we have landed a few other optims. Like walker, at least. (blame me, so reassigning)
Assignee: peterv → axel
Target Milestone: --- → Future
Comment 17•20 years ago
|
||
*** Bug 272565 has been marked as a duplicate of this bug. ***
Comment 18•20 years ago
|
||
could you just share the spidermonkey stack handling stuff?
that's not an issue any more since we no longer use up stack to do recursion, instead we use up heap.
Comment 20•18 years ago
|
||
My use case is that I have a manager webapp (using java and tomcat) that monitors and/or filters XML files that are called into a client side XSL transformation using the document function. I was doing a simple response.sendRedirect which was sending a 302 code. I have worked around this by using a RequestDispatcher and forwarding the request. I would prefer to do the simple redirect as I now have to get the context of a child webapp and forward to it.
Comment 21•18 years ago
|
||
The last message was sent to the wrong bug. Don't know how I got here??
Updated•15 years ago
|
QA Contact: keith → xslt
Reporter | ||
Updated•7 years ago
|
Assignee: axel → nobody
Updated•2 years ago
|
Severity: normal → S3
You need to log in
before you can comment on or make changes to this bug.
Description
•