8218227: StringBuilder/StringBuffer constructor throws confusing NegativeArraySizeException
Reviewed-by: rriggs
--- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Wed Feb 06 00:20:37 2019 +0100
+++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Tue Feb 05 17:05:40 2019 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -92,6 +92,19 @@
}
/**
+ * Creates an AbstractStringBuilder with the specified coder and with
+ * the initial capacity equal to the smaller of (capacity + addition)
+ * and Integer.MAX_VALUE.
+ */
+ AbstractStringBuilder(byte coder, int capacity, int addition) {
+ this.coder = coder;
+ capacity = (capacity < Integer.MAX_VALUE - addition)
+ ? capacity + addition : Integer.MAX_VALUE;
+ value = (coder == LATIN1)
+ ? new byte[capacity] : StringUTF16.newBytesFor(capacity);
+ }
+
+ /**
* Compares the objects of two AbstractStringBuilder implementations lexicographically.
*
* @since 11
--- a/src/java.base/share/classes/java/lang/StringBuffer.java Wed Feb 06 00:20:37 2019 +0100
+++ b/src/java.base/share/classes/java/lang/StringBuffer.java Tue Feb 05 17:05:40 2019 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2018, 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
@@ -148,7 +148,7 @@
*/
@HotSpotIntrinsicCandidate
public StringBuffer(String str) {
- super(str.length() + 16);
+ super(str.coder(), str.length(), 16);
append(str);
}
@@ -166,7 +166,7 @@
* @since 1.5
*/
public StringBuffer(CharSequence seq) {
- this(seq.length() + 16);
+ super(String.LATIN1, seq.length(), 16);
append(seq);
}
--- a/src/java.base/share/classes/java/lang/StringBuilder.java Wed Feb 06 00:20:37 2019 +0100
+++ b/src/java.base/share/classes/java/lang/StringBuilder.java Tue Feb 05 17:05:40 2019 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -121,7 +121,7 @@
*/
@HotSpotIntrinsicCandidate
public StringBuilder(String str) {
- super(str.length() + 16);
+ super(str.coder(), str.length(), 16);
append(str);
}
@@ -134,7 +134,7 @@
* @param seq the sequence to copy.
*/
public StringBuilder(CharSequence seq) {
- this(seq.length() + 16);
+ super(String.LATIN1, seq.length(), 16);
append(seq);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/StringBuffer/HugeCapacity.java Tue Feb 05 17:05:40 2019 -0800
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8218227
+ * @summary StringBuilder/StringBuffer constructor throws confusing
+ * NegativeArraySizeException
+ * @requires os.maxMemory >= 6G
+ * @run main/othervm -Xms5G -Xmx5G HugeCapacity
+ * @ignore This test has huge memory requirements
+ */
+
+public class HugeCapacity {
+ private static int failures = 0;
+
+ public static void main(String[] args) {
+ testHugeInitialString();
+ testHugeInitialCharSequence();
+ if (failures > 0) {
+ throw new RuntimeException(failures + " tests failed");
+ }
+ }
+
+ private static void testHugeInitialString() {
+ try {
+ String str = "Z".repeat(Integer.MAX_VALUE - 8);
+ StringBuffer sb = new StringBuffer(str);
+ } catch (OutOfMemoryError ignore) {
+ } catch (Throwable unexpected) {
+ unexpected.printStackTrace();
+ failures++;
+ }
+ }
+
+ private static void testHugeInitialCharSequence() {
+ try {
+ CharSequence seq = new MyHugeCharSeq();
+ StringBuffer sb = new StringBuffer(seq);
+ } catch (OutOfMemoryError ignore) {
+ } catch (Throwable unexpected) {
+ unexpected.printStackTrace();
+ failures++;
+ }
+ }
+
+ private static class MyHugeCharSeq implements CharSequence {
+ public char charAt(int i) {
+ throw new UnsupportedOperationException();
+ }
+ public int length() { return Integer.MAX_VALUE; }
+ public CharSequence subSequence(int st, int e) {
+ throw new UnsupportedOperationException();
+ }
+ public String toString() { return ""; }
+ }
+}
--- a/test/jdk/java/lang/StringBuilder/HugeCapacity.java Wed Feb 06 00:20:37 2019 +0100
+++ b/test/jdk/java/lang/StringBuilder/HugeCapacity.java Tue Feb 05 17:05:40 2019 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -23,10 +23,11 @@
/**
* @test
- * @bug 8149330
+ * @bug 8149330 8218227
* @summary Capacity should not get close to Integer.MAX_VALUE unless
* necessary
- * @run main/othervm -Xmx5G HugeCapacity
+ * @requires os.maxMemory >= 6G
+ * @run main/othervm -Xms5G -Xmx5G HugeCapacity
* @ignore This test has huge memory requirements
*/
@@ -36,6 +37,8 @@
public static void main(String[] args) {
testLatin1();
testUtf16();
+ testHugeInitialString();
+ testHugeInitialCharSequence();
if (failures > 0) {
throw new RuntimeException(failures + " tests failed");
}
@@ -63,4 +66,37 @@
failures++;
}
}
+
+ private static void testHugeInitialString() {
+ try {
+ String str = "Z".repeat(Integer.MAX_VALUE - 8);
+ StringBuilder sb = new StringBuilder(str);
+ } catch (OutOfMemoryError ignore) {
+ } catch (Throwable unexpected) {
+ unexpected.printStackTrace();
+ failures++;
+ }
+ }
+
+ private static void testHugeInitialCharSequence() {
+ try {
+ CharSequence seq = new MyHugeCharSeq();
+ StringBuilder sb = new StringBuilder(seq);
+ } catch (OutOfMemoryError ignore) {
+ } catch (Throwable unexpected) {
+ unexpected.printStackTrace();
+ failures++;
+ }
+ }
+
+ private static class MyHugeCharSeq implements CharSequence {
+ public char charAt(int i) {
+ throw new UnsupportedOperationException();
+ }
+ public int length() { return Integer.MAX_VALUE; }
+ public CharSequence subSequence(int st, int e) {
+ throw new UnsupportedOperationException();
+ }
+ public String toString() { return ""; }
+ }
}