From 90c48c8f2afbbf252c3fe643c01580487fc5f14f Mon Sep 17 00:00:00 2001
From: Florian Angerer <florian.angerer@oracle.com>
Date: Fri, 15 Dec 2017 11:27:17 +0100
Subject: [PATCH] Abort if a single line is too large.

---
 .../packages/analyzer/FileLineIterator.java   | 73 ++++++++++++++++---
 1 file changed, 62 insertions(+), 11 deletions(-)

diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/FileLineIterator.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/FileLineIterator.java
index 9ad1f288a5..1dfd9ba956 100644
--- a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/FileLineIterator.java
+++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/FileLineIterator.java
@@ -24,25 +24,36 @@ package com.oracle.truffle.r.test.packages.analyzer;
 
 import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.NoSuchElementException;
+import java.util.logging.Logger;
 
 public class FileLineIterator extends LineIterator {
 
-    /** Maximum number of lines that will be analyzed. */
-    public static final int MAX_LINES = 500000;
+    private static final Logger LOGGER = Logger.getLogger(FileLineIterator.class.getName());
+
+    /** 100 MB */
+    public static final int MAX_FILE_SIZE = 200 * 1024 * 1024;
 
-    private int cnt = 0;
     private BufferedReader reader;
     private String lookahead = null;
 
     public FileLineIterator(Path p) {
         try {
-            this.reader = Files.newBufferedReader(p);
-            nextLine();
+            long size = Files.size(p);
+            if (size < MAX_FILE_SIZE) {
+                this.reader = Files.newBufferedReader(p);
+                nextLine();
+            } else {
+                this.reader = new BufferedReader(new InputStreamReader(new LimitSizeInputStreamReader(Files.newInputStream(p), MAX_FILE_SIZE)));
+                LOGGER.warning(String.format("Will read at most %d bytes from file %s.", size, p));
+                this.reader = null;
+            }
         } catch (IOException e) {
-            // ignore
+            LOGGER.severe(String.format("I/O error occurred when reading %s: %s", p, e.getMessage()));
         }
     }
 
@@ -55,21 +66,21 @@ public class FileLineIterator extends LineIterator {
 
     private String nextLine() {
 
-        if (cnt++ >= MAX_LINES) {
-            return null;
-        }
         String line = lookahead;
         try {
             lookahead = reader.readLine();
+        } catch (OutOfMemoryError e) {
+            // If a single line is just too large, abort.
+            lookahead = null;
         } catch (IOException e) {
-
+            lookahead = null;
         }
         return line;
     }
 
     @Override
     public boolean hasNext() {
-        return cnt < MAX_LINES && lookahead != null;
+        return lookahead != null;
     }
 
     @Override
@@ -79,4 +90,44 @@ public class FileLineIterator extends LineIterator {
         }
         throw new NoSuchElementException();
     }
+
+    private static class LimitSizeInputStreamReader extends InputStream {
+
+        private final long limit;
+        private final InputStream source;
+        private long consumed;
+
+        protected LimitSizeInputStreamReader(InputStream source, long limit) {
+            this.source = source;
+            this.limit = limit;
+        }
+
+        @Override
+        public int read() throws IOException {
+            if (consumed < limit) {
+                consumed++;
+                return source.read();
+            }
+            return -1;
+        }
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            return read(b, 0, b.length);
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            int read = super.read(b, off, (int) Math.min(limit - consumed, len));
+            consumed += read;
+            return read;
+        }
+
+        @Override
+        public int available() throws IOException {
+            return Math.min((int) (limit - consumed), super.available());
+        }
+
+    }
+
 }
-- 
GitLab