OpenJDK / portola / portola
changeset 38953:2cd777b7c655
8139414: java.util.Scanner hasNext() returns true, next() throws NoSuchElementException
8072582: Scanner delimits incorrectly when delimiter spans a buffer boundary
Reviewed-by: smarks
author | sherman |
---|---|
date | Tue, 14 Jun 2016 16:56:27 -0700 |
parents | ca428fb526d4 |
children | a5bac7d9a6ba |
files | jdk/src/java.base/share/classes/java/util/Scanner.java jdk/test/java/util/Scanner/ScanTest.java |
diffstat | 2 files changed, 71 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/src/java.base/share/classes/java/util/Scanner.java Tue Jun 14 10:27:23 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/util/Scanner.java Tue Jun 14 16:56:27 2016 -0700 @@ -793,7 +793,6 @@ private void readInput() { if (buf.limit() == buf.capacity()) makeSpace(); - // Prepare to receive data int p = buf.position(); buf.position(buf.limit()); @@ -806,15 +805,12 @@ lastException = ioe; n = -1; } - if (n == -1) { sourceClosed = true; needInput = false; } - if (n > 0) needInput = false; - // Restore current position and limit for reading buf.limit(buf.position()); buf.position(p); @@ -871,15 +867,20 @@ matchValid = false; matcher.usePattern(delimPattern); matcher.region(position, buf.limit()); - // Skip delims first - if (matcher.lookingAt()) + if (matcher.lookingAt()) { + if (matcher.hitEnd() && !sourceClosed) { + // more input might change the match of delims, in which + // might change whether or not if there is token left in + // buffer (don't update the "position" in this case) + needInput = true; + return false; + } position = matcher.end(); - + } // If we are sitting at the end, no more tokens in buffer if (position == buf.limit()) return false; - return true; } @@ -900,7 +901,6 @@ */ private String getCompleteTokenInBuffer(Pattern pattern) { matchValid = false; - // Skip delims first matcher.usePattern(delimPattern); if (!skipped) { // Enforcing only one skip of leading delims @@ -941,13 +941,16 @@ foundNextDelim = matcher.find(); } if (foundNextDelim) { - // In the rare case that more input could cause the match - // to be lost and there is more input coming we must wait - // for more input. Note that hitting the end is okay as long - // as the match cannot go away. It is the beginning of the - // next delims we want to be sure about, we don't care if - // they potentially extend further. - if (matcher.requireEnd() && !sourceClosed) { + // In two rare cases that more input might cause the match to be + // lost or change. + // (1) if requireEnd() is true, more input might cause the match + // to be lost, we must wait for more input. + // (2) while hitting the end is okay IF the match does not + // go away AND the beginning of the next delims does not change + // (we don't care if they potentially extend further). But it's + // possible that more input could cause the beginning of the + // delims change, so have to wait for more input as well. + if ((matcher.requireEnd() || matcher.hitEnd()) && !sourceClosed) { needInput = true; return null; } @@ -1341,8 +1344,9 @@ saveState(); modCount++; while (!sourceClosed) { - if (hasTokenInBuffer()) + if (hasTokenInBuffer()) { return revertState(true); + } readInput(); } boolean result = hasTokenInBuffer(); @@ -1365,7 +1369,6 @@ ensureOpen(); clearCaches(); modCount++; - while (true) { String token = getCompleteTokenInBuffer(null); if (token != null) {
--- a/jdk/test/java/util/Scanner/ScanTest.java Tue Jun 14 10:27:23 2016 -0700 +++ b/jdk/test/java/util/Scanner/ScanTest.java Tue Jun 14 16:56:27 2016 -0700 @@ -24,7 +24,7 @@ /** * @test * @bug 4313885 4926319 4927634 5032610 5032622 5049968 5059533 6223711 6277261 6269946 6288823 - * 8072722 + * 8072722 8072582 8139414 * @summary Basic tests of java.util.Scanner methods * @key randomness * @modules jdk.localedata @@ -70,6 +70,7 @@ ioExceptionTest(); matchTest(); delimiterTest(); + boundaryDelimTest(); useLocaleTest(); closeTest(); cacheTest(); @@ -504,6 +505,54 @@ report("Single delim test"); } + private static void append(StringBuilder sb, char c, int n) { + for (int i = 0; i < n; i++) { + sb.append(c); + } + } + + public static void boundaryDelimTest() throws Exception { + // 8072582 + StringBuilder sb = new StringBuilder(); + append(sb, 'a', 228); sb.append(","); + append(sb, 'b', 293); sb.append("#,#"); + append(sb, 'c', 308); sb.append(","); + append(sb, 'd', 188); sb.append("#,#"); + append(sb, 'e', 2); + try (Scanner scanner = new Scanner(sb.toString())) { + scanner.useDelimiter("(#,#)|(,)"); + while(scanner.hasNext()){ + String next = scanner.next(); + if(next.contains("#")){ + System.out.printf("[%s]%n", next); + failCount++; + } + } + } + + // 8139414 + int i = 1019; + sb = new StringBuilder(); + sb.append("--;"); + for (int j = 0; j < 1019; ++j) { + sb.append(j%10); + } + sb.append("-;-"); + String text = sb.toString(); + try (Scanner scanner = new Scanner(text)) { + scanner.useDelimiter("-;(-)?"); + while (scanner.hasNext()) { + scanner.next(); + } + } catch (NoSuchElementException e) { + System.out.println("Caught NoSuchElementException " + e); + e.printStackTrace(); + failCount++; + } + + report("delim at boundary test"); + } + /* * The hasNextPattern caches a match of a pattern called the regular cache * The hasNextType caches a match of that type called the type cache