8230342: LineNumberReader.getLineNumber() returns inconsistent results after EOF
authorbpb
Wed, 11 Sep 2019 12:32:01 -0700
changeset 58089 e64fec9f1773
parent 58088 e2de6e166880
child 58090 91bc4d6c4054
8230342: LineNumberReader.getLineNumber() returns inconsistent results after EOF Reviewed-by: rriggs, dfuchs
src/java.base/share/classes/java/io/BufferedReader.java
src/java.base/share/classes/java/io/LineNumberReader.java
test/jdk/java/io/LineNumberReader/Read.java
--- a/src/java.base/share/classes/java/io/BufferedReader.java	Wed Sep 11 11:55:31 2019 -0700
+++ b/src/java.base/share/classes/java/io/BufferedReader.java	Wed Sep 11 12:32:01 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -302,6 +302,8 @@
      * (EOF).
      *
      * @param      ignoreLF  If true, the next '\n' will be skipped
+     * @param      term      Output: Whether a line terminator was encountered
+     *                       while reading the line; may be {@code null}.
      *
      * @return     A String containing the contents of the line, not including
      *             any line-termination characters, or null if the end of the
@@ -311,13 +313,14 @@
      *
      * @exception  IOException  If an I/O error occurs
      */
-    String readLine(boolean ignoreLF) throws IOException {
+    String readLine(boolean ignoreLF, boolean[] term) throws IOException {
         StringBuffer s = null;
         int startChar;
 
         synchronized (lock) {
             ensureOpen();
             boolean omitLF = ignoreLF || skipLF;
+            if (term != null) term[0] = false;
 
         bufferLoop:
             for (;;) {
@@ -344,6 +347,7 @@
                 for (i = nextChar; i < nChars; i++) {
                     c = cb[i];
                     if ((c == '\n') || (c == '\r')) {
+                        if (term != null) term[0] = true;
                         eol = true;
                         break charLoop;
                     }
@@ -389,7 +393,7 @@
      * @see java.nio.file.Files#readAllLines
      */
     public String readLine() throws IOException {
-        return readLine(false);
+        return readLine(false, null);
     }
 
     /**
--- a/src/java.base/share/classes/java/io/LineNumberReader.java	Wed Sep 11 11:55:31 2019 -0700
+++ b/src/java.base/share/classes/java/io/LineNumberReader.java	Wed Sep 11 12:32:01 2019 -0700
@@ -25,7 +25,6 @@
 
 package java.io;
 
-
 /**
  * A buffered character-input stream that keeps track of line numbers.  This
  * class defines methods {@link #setLineNumber(int)} and {@link
@@ -200,9 +199,10 @@
      */
     public String readLine() throws IOException {
         synchronized (lock) {
-            String l = super.readLine(skipLF);
+            boolean[] term = new boolean[1];
+            String l = super.readLine(skipLF, term);
             skipLF = false;
-            if (l != null)
+            if (l != null && term[0])
                 lineNumber++;
             return l;
         }
--- a/test/jdk/java/io/LineNumberReader/Read.java	Wed Sep 11 11:55:31 2019 -0700
+++ b/test/jdk/java/io/LineNumberReader/Read.java	Wed Sep 11 12:32:01 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,16 +22,24 @@
  */
 
 /* @test
-   @bug 4074875 4063511
+   @bug 4074875 4063511 8230342
    @summary Make sure LineNumberReader.read(char, int , int) will increase
             the linenumber correctly.
    */
 
-import java.io.*;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import java.util.function.Consumer;
 
 public class Read {
 
     public static void main(String[] args) throws Exception {
+        testReadChars();
+        testEofs();
+    }
+
+    private static void testReadChars() throws Exception {
         String s = "aaaa\nbbb\n";
         char[] buf = new char[5];
         int n = 0;
@@ -49,4 +57,49 @@
             throw new Exception("Failed test: Expected line number: 2, got "
                                 + line);
     }
+
+    private static void testEofs() throws Exception {
+        String string = "first \n second";
+
+        Consumer<LineNumberReader> c = (LineNumberReader r) -> {
+            try {
+                while (r.read() != -1)
+                    continue;
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        };
+        testEof(c, string, 1);
+
+        c = (LineNumberReader r) -> {
+            try {
+                char[] buf = new char[128];
+                while (r.read(buf) != -1)
+                    continue;
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        };
+        testEof(c, string, 1);
+
+        c = (LineNumberReader r) -> {
+            try {
+                while (r.readLine() != null)
+                    continue;
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        };
+        testEof(c, string, 1);
+    }
+
+    private static void testEof(Consumer<LineNumberReader> c, String s, int n)
+        throws Exception {
+        LineNumberReader r = new LineNumberReader(new StringReader(s));
+        c.accept(r);
+        int line;
+        if ((line = r.getLineNumber()) != n)
+            throw new Exception("Failed test: Expected line number: " + n  +
+                " , got " + line);
+    }
 }