Fix for Bugzilla entries 6833 7023 7123 7410 Basic summary of logic error: It is possible for multiple RTF DTMs to be pushed onto the stack between the start of a template and return from it. I hadn't anticipated that, so my pop logic was inadequate. I'm still not 110% sure I understand the case where this situation arises... I have a general intuition that it makes sense, but also a suspicion that there might be a way to avoid creating one of these DTMs. We should review that someday. Meanwhile, this fixes a whole batch of related bugs.
diff --git a/src/org/apache/xpath/XPathContext.java b/src/org/apache/xpath/XPathContext.java index ffe4fdb..d6070e3 100644 --- a/src/org/apache/xpath/XPathContext.java +++ b/src/org/apache/xpath/XPathContext.java
@@ -110,6 +110,7 @@ import org.apache.xml.utils.SAXSourceLocator; import org.apache.xml.utils.XMLString; import org.apache.xml.utils.XMLStringFactory; +import org.apache.xml.utils.IntStack; import org.apache.xpath.axes.DescendantIterator; @@ -124,6 +125,7 @@ */ public class XPathContext extends DTMManager // implements ExpressionContext { + IntStack m_last_pushed_rtfdtm=new IntStack(); /** * Stack of cached "reusable" DTMs for Result Tree Fragments. * This is a kluge to handle the problem of starting an RTF before @@ -1270,6 +1272,10 @@ m_rtfdtm_stack.addElement(rtfdtm); ++m_which_rtfdtm; } + else if(m_which_rtfdtm<0) + { + rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.elementAt(++m_which_rtfdtm); + } else { rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.elementAt(m_which_rtfdtm); @@ -1277,8 +1283,9 @@ // It might already be under construction -- the classic example would be // an xsl:variable which uses xsl:call-template as part of its value. To // handle this recursion, we have to start a new RTF DTM, pushing the old - // one onto a stack so we can return to it. It is hoped that - // this is an uncommon case! + // one onto a stack so we can return to it. This is not as uncommon a case + // as we might wish, unfortunately, as some folks insist on coding XSLT + // as if it were a procedural language... if(rtfdtm.isTreeIncomplete()) { if(++m_which_rtfdtm < m_rtfdtm_stack.size()) @@ -1290,6 +1297,7 @@ } } } + return rtfdtm; } @@ -1299,6 +1307,7 @@ * */ public void pushRTFContext() { + m_last_pushed_rtfdtm.push(m_which_rtfdtm); if(null!=m_rtfdtm_stack) ((SAX2RTFDTM)(getRTFDTM())).pushRewindMark(); } @@ -1321,11 +1330,22 @@ { if(null==m_rtfdtm_stack) return; - - boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.elementAt(m_which_rtfdtm))).popRewindMark(); - if(isEmpty && m_which_rtfdtm>0) - { - --m_which_rtfdtm; - } + + int previous=m_last_pushed_rtfdtm.pop(); + if(m_which_rtfdtm==previous) + { + if(previous>=0) // guard against none-active + { + boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.elementAt(previous))).popRewindMark(); + } + } + else while(m_which_rtfdtm!=previous) + { + // Empty each DTM before popping, so it's ready for reuse + // _DON'T_ pop the previous, since it's still open (which is why we + // stacked up more of these) and did not receive a mark. + boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.elementAt(m_which_rtfdtm))).popRewindMark(); + --m_which_rtfdtm; + } } }