001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: StackGuard.java 468645 2006-10-28 06:57:24Z minchau $ 020 */ 021 package org.apache.xalan.transformer; 022 023 import javax.xml.transform.TransformerException; 024 025 import org.apache.xalan.res.XSLMessages; 026 import org.apache.xalan.templates.Constants; 027 import org.apache.xalan.templates.ElemTemplate; 028 import org.apache.xalan.templates.ElemTemplateElement; 029 import org.apache.xml.utils.ObjectStack; 030 031 /** 032 * Class to guard against recursion getting too deep. 033 */ 034 public class StackGuard 035 { 036 037 /** 038 * Used for infinite loop check. If the value is -1, do not 039 * check for infinite loops. Anyone who wants to enable that 040 * check should change the value of this variable to be the 041 * level of recursion that they want to check. Be careful setting 042 * this variable, if the number is too low, it may report an 043 * infinite loop situation, when there is none. 044 * Post version 1.0.0, we'll make this a runtime feature. 045 */ 046 private int m_recursionLimit = -1; 047 048 TransformerImpl m_transformer; 049 050 /** 051 * Get the recursion limit. 052 * Used for infinite loop check. If the value is -1, do not 053 * check for infinite loops. Anyone who wants to enable that 054 * check should change the value of this variable to be the 055 * level of recursion that they want to check. Be careful setting 056 * this variable, if the number is too low, it may report an 057 * infinite loop situation, when there is none. 058 * Post version 1.0.0, we'll make this a runtime feature. 059 * 060 * @return The recursion limit. 061 */ 062 public int getRecursionLimit() 063 { 064 return m_recursionLimit; 065 } 066 067 /** 068 * Set the recursion limit. 069 * Used for infinite loop check. If the value is -1, do not 070 * check for infinite loops. Anyone who wants to enable that 071 * check should change the value of this variable to be the 072 * level of recursion that they want to check. Be careful setting 073 * this variable, if the number is too low, it may report an 074 * infinite loop situation, when there is none. 075 * Post version 1.0.0, we'll make this a runtime feature. 076 * 077 * @param limit The recursion limit. 078 */ 079 public void setRecursionLimit(int limit) 080 { 081 m_recursionLimit = limit; 082 } 083 084 /** 085 * Constructor StackGuard 086 * 087 */ 088 public StackGuard(TransformerImpl transformerImpl) 089 { 090 m_transformer = transformerImpl; 091 } 092 093 /** 094 * Overide equal method for StackGuard objects 095 * 096 */ 097 public int countLikeTemplates(ElemTemplate templ, int pos) 098 { 099 ObjectStack elems = m_transformer.getCurrentTemplateElements(); 100 int count = 1; 101 for (int i = pos-1; i >= 0; i--) 102 { 103 if((ElemTemplateElement)elems.elementAt(i) == templ) 104 count++; 105 } 106 107 return count; 108 } 109 110 111 /** 112 * Get the next named or match template down from and including 113 * the given position. 114 * @param pos the current index position in the stack. 115 * @return null if no matched or named template found, otherwise 116 * the next named or matched template at or below the position. 117 */ 118 private ElemTemplate getNextMatchOrNamedTemplate(int pos) 119 { 120 ObjectStack elems = m_transformer.getCurrentTemplateElements(); 121 for (int i = pos; i >= 0; i--) 122 { 123 ElemTemplateElement elem = (ElemTemplateElement) elems.elementAt(i); 124 if(null != elem) 125 { 126 if(elem.getXSLToken() == Constants.ELEMNAME_TEMPLATE) 127 { 128 return (ElemTemplate)elem; 129 } 130 } 131 } 132 return null; 133 } 134 135 /** 136 * Check if we are in an infinite loop 137 * 138 * @throws TransformerException 139 */ 140 public void checkForInfinateLoop() throws TransformerException 141 { 142 int nTemplates = m_transformer.getCurrentTemplateElementsCount(); 143 if(nTemplates < m_recursionLimit) 144 return; 145 146 if(m_recursionLimit <= 0) 147 return; // Safety check. 148 149 // loop from the top index down to the recursion limit (I don't think 150 // there's any need to go below that). 151 for (int i = (nTemplates - 1); i >= m_recursionLimit; i--) 152 { 153 ElemTemplate template = getNextMatchOrNamedTemplate(i); 154 155 if(null == template) 156 break; 157 158 int loopCount = countLikeTemplates(template, i); 159 160 if (loopCount >= m_recursionLimit) 161 { 162 // throw new TransformerException("Template nesting too deep. nesting = "+loopCount+ 163 // ", template "+((null == template.getName()) ? "name = " : "match = ")+ 164 // ((null != template.getName()) ? template.getName().toString() 165 // : template.getMatch().getPatternString())); 166 167 String idIs = XSLMessages.createMessage(((null != template.getName()) ? "nameIs" : "matchPatternIs"), null); 168 Object[] msgArgs = new Object[]{ new Integer(loopCount), idIs, 169 ((null != template.getName()) ? template.getName().toString() 170 : template.getMatch().getPatternString()) }; 171 String msg = XSLMessages.createMessage("recursionTooDeep", msgArgs); 172 173 throw new TransformerException(msg); 174 } 175 } 176 } 177 178 }