Author: cbrisson
Date: Sun Oct 14 16:58:57 2018
New Revision: 1843853

URL: http://svn.apache.org/viewvc?rev=1843853&view=rev
Log:
[VELOCITY-886] Avoid OOM in large integer loops

Modified:
    
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIntegerRange.java
    
velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/compare/range.cmp
    
velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/range.vm

Modified: 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIntegerRange.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIntegerRange.java?rev=1843853&r1=1843852&r2=1843853&view=diff
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIntegerRange.java
 (original)
+++ 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIntegerRange.java
 Sun Oct 14 16:58:57 2018
@@ -26,8 +26,9 @@ import org.apache.velocity.runtime.parse
 import org.apache.velocity.util.DuckType;
 import org.apache.velocity.util.StringUtils;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.AbstractList;
+import java.util.Iterator;
+import java.util.ListIterator;
 
 /**
  * handles the range 'operator'  [ n .. m ]
@@ -64,6 +65,141 @@ public class ASTIntegerRange extends Sim
         return visitor.visit(this, data);
     }
 
+    public static class IntegerRange extends AbstractList<Integer>
+    {
+        public class RangeIterator implements ListIterator<Integer>
+        {
+            private int value;
+
+            public RangeIterator()
+            {
+                value = left - delta;
+            }
+
+            public RangeIterator(int startIndex)
+            {
+                value = left + (startIndex - 1) * delta;
+            }
+
+            @Override
+            public Integer next()
+            {
+                value += delta;
+                return value;
+            }
+
+            @Override
+            public boolean hasPrevious()
+            {
+                return value != left - delta;
+            }
+
+            @Override
+            public Integer previous()
+            {
+                value -= delta;
+                return value;
+            }
+
+            @Override
+            public int nextIndex()
+            {
+                return (value + delta - left) * delta;
+            }
+
+            @Override
+            public int previousIndex()
+            {
+                return (value - delta - left) * delta;
+            }
+
+            @Override
+            public void remove()
+            {
+                throw new UnsupportedOperationException("integer range is read 
only");
+            }
+
+            @Override
+            public void set(Integer integer)
+            {
+                throw new UnsupportedOperationException("integer range is read 
only");
+            }
+
+            @Override
+            public void add(Integer integer)
+            {
+                throw new UnsupportedOperationException("integer range is read 
only");
+            }
+
+            @Override
+            public boolean hasNext()
+            {
+                return value != right;
+            }
+        }
+
+        private int left;
+        private int right;
+        private int delta;
+
+        public IntegerRange(int left, int right, int delta)
+        {
+            this.left = left;
+            this.right = right;
+            this.delta = delta;
+        }
+
+        @Override
+        public Iterator<Integer> iterator()
+        {
+            return new RangeIterator();
+        }
+
+        @Override
+        public Integer get(int index)
+        {
+            int ret = left + delta * index;
+            if (delta > 0 && ret > right || delta < 0 && ret < right)
+            {
+                throw new IndexOutOfBoundsException();
+            }
+            return ret;
+        }
+
+        @Override
+        public int indexOf(Object o)
+        {
+            int v = DuckType.asNumber(o).intValue();
+            v -= left;
+            v *= delta;
+            return v >= 0 && v < size() ? v : -1;
+        }
+
+        @Override
+        public int lastIndexOf(Object o)
+        {
+            return indexOf(o);
+        }
+
+        @Override
+        public ListIterator<Integer> listIterator()
+        {
+            return new RangeIterator();
+        }
+
+        @Override
+        public ListIterator<Integer> listIterator(int index)
+        {
+            return new RangeIterator(index);
+        }
+
+        @Override
+        public int size()
+        {
+            return Math.abs(right - left) + 1;
+        }
+    }
+
     /**
      *  does the real work.  Creates an Vector of Integers with the
      *  right value range
@@ -123,7 +259,6 @@ public class ASTIntegerRange extends Sim
             return null;
         }
 
-
         /*
          *  get the two integer values of the ends of the range
          */
@@ -132,32 +267,16 @@ public class ASTIntegerRange extends Sim
         int r = ((Number) right).intValue();
 
         /*
-         *  find out how many there are
-         */
-
-        int nbrElements = Math.abs( l - r );
-        nbrElements += 1;
-
-        /*
          *  Determine whether the increment is positive or negative.
          */
 
         int delta = ( l >= r ) ? -1 : 1;
 
         /*
-         * Fill the range with the appropriate values.
+         * Return the corresponding integer range
          */
 
-        List elements = new ArrayList(nbrElements);
-        int value = l;
-
-        for (int i = 0; i < nbrElements; i++)
-        {
-            elements.add(value);
-            value += delta;
-        }
-
-        return elements;
+        return new IntegerRange(l, r, delta);
     }
 
     /**

Modified: 
velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/compare/range.cmp
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/compare/range.cmp?rev=1843853&r1=1843852&r2=1843853&view=diff
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/compare/range.cmp
 (original)
+++ 
velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/compare/range.cmp
 Sun Oct 14 16:58:57 2018
@@ -54,4 +54,9 @@ Now some use-case examples.  Suppose we
 <tr><td>&nbsp;</td></tr>
 <tr><td>&nbsp;</td></tr>
 </table>
+
+----
+Wide loop should not OOM
+that's enough
+
 =done=

Modified: 
velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/range.vm
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/range.vm?rev=1843853&r1=1843852&r2=1843853&view=diff
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/range.vm
 (original)
+++ 
velocity/engine/trunk/velocity-engine-core/src/test/resources/templates/range.vm
 Sun Oct 14 16:58:57 2018
@@ -80,4 +80,14 @@ Now some use-case examples.  Suppose we
 <tr><td>&nbsp;</td></tr>
 #end
 </table>
+
+----
+Wide loop should not OOM
+#foreach($i in [0..67000000])
+#if($i == 100)
+that's enough
+#break
+#end
+#end
+
 =done=


Reply via email to