--- old/src/java.base/share/classes/java/io/DataOutputStream.java 2019-03-15 14:04:56.000000000 -0700 +++ new/src/java.base/share/classes/java/io/DataOutputStream.java 2019-03-15 14:04:56.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -345,12 +345,11 @@ */ static int writeUTF(String str, DataOutput out) throws IOException { int strlen = str.length(); - int utflen = 0; - int c, count = 0; - /* use charAt instead of copying String to char array */ - for (int i = 0; i < strlen; i++) { - c = str.charAt(i); + // use charAt instead of copying String to char array + int utflen = 0; + for (int i = 0; i < strlen && utflen < 65536; i++) { + int c = str.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { utflen++; } else if (c > 0x07FF) { @@ -361,8 +360,7 @@ } if (utflen > 65535) - throw new UTFDataFormatException( - "encoded string too long: " + utflen + " bytes"); + throw new UTFDataFormatException("encoded string too long"); byte[] bytearr = null; if (out instanceof DataOutputStream) { @@ -374,18 +372,19 @@ bytearr = new byte[utflen+2]; } + int count = 0; bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF); bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF); int i=0; for (i=0; i= 0x0001) && (c <= 0x007F))) break; - bytearr[count++] = (byte) c; + int c = str.charAt(i); + if (!((c >= 0x0001) && (c <= 0x007F))) break; + bytearr[count++] = (byte) c; } for (;i < strlen; i++){ - c = str.charAt(i); + int c = str.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { bytearr[count++] = (byte) c; --- old/test/jdk/java/io/DataOutputStream/WriteUTF.java 2019-03-15 14:04:57.000000000 -0700 +++ new/test/jdk/java/io/DataOutputStream/WriteUTF.java 2019-03-15 14:04:57.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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,14 +22,22 @@ */ /* @test - @bug 4260284 - @summary Test if DataOutputStream will overcount written field. -*/ + * @bug 4260284 8219196 + * @summary Test if DataOutputStream will overcount written field. + * @requires os.maxMemory > 4g + * @run testng/othervm -Xmx4g WriteUTF + */ + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UTFDataFormatException; -import java.io.*; +import org.testng.annotations.Test; public class WriteUTF { - public static void main(String[] args) throws Exception { + @Test + public static void overcountWrittenField() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); dos.writeUTF("Hello, World!"); // 15 @@ -37,4 +45,25 @@ if (baos.size() != dos.size()) throw new RuntimeException("Miscounted bytes in DataOutputStream."); } + + private static void writeUTF(int size) throws IOException { + // this character gives 3 bytes when encoded using UTF-8 + String s = "\u0800".repeat(size); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(bos); + dos.writeUTF(s); + } + + @Test(expectedExceptions = UTFDataFormatException.class) + public void utfDataFormatException() throws IOException { + writeUTF(1 << 16); + } + + // Without 8219196 fix, throws ArrayIndexOutOfBoundsException instead of + // expected UTFDataFormatException. Requires 4GB of heap (-Xmx4g) to run + // without throwing an OutOfMemoryError. + @Test(expectedExceptions = UTFDataFormatException.class) + public void arrayIndexOutOfBoundsException() throws IOException { + writeUTF(Integer.MAX_VALUE / 3 + 1); + } }