8230743: StringJoiner does not handle too large strings correctly

Reviewed-by: rriggs, psandoz, martin
This commit is contained in:
Jim Laskey 2020-06-05 09:37:14 -03:00
parent cb960ee7b5
commit 4de4200652
3 changed files with 77 additions and 2 deletions

View File

@ -125,6 +125,7 @@ public final class StringJoiner {
this.prefix = prefix.toString();
this.delimiter = delimiter.toString();
this.suffix = suffix.toString();
checkAddLength(0, 0);
}
/**
@ -202,13 +203,22 @@ public final class StringJoiner {
} else {
if (size == elts.length)
elts = Arrays.copyOf(elts, 2 * size);
len += delimiter.length();
len = checkAddLength(len, delimiter.length());
}
len += elt.length();
len = checkAddLength(len, elt.length());
elts[size++] = elt;
return this;
}
private int checkAddLength(int oldLen, int inc) {
long newLen = (long)oldLen + (long)inc;
long tmpLen = newLen + (long)prefix.length() + (long)suffix.length();
if (tmpLen != (int)tmpLen) {
throw new OutOfMemoryError("Requested array size exceeds VM limit");
}
return (int)newLen;
}
/**
* Adds the contents of the given {@code StringJoiner} without prefix and
* suffix as the next element if it is non-empty. If the given {@code

View File

@ -25,12 +25,14 @@
* @test
* @bug 8017231 8020977 8054221
* @summary test StringJoiner::merge
* @modules java.base/jdk.internal.util
* @run testng MergeTest
*/
import java.util.StringJoiner;
import java.util.stream.Stream;
import org.testng.annotations.Test;
import static jdk.internal.util.ArraysSupport.MAX_ARRAY_LENGTH;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
@ -167,4 +169,19 @@ public class MergeTest {
assertEquals(sj.merge(sj).toString(), fixes.pre0 + "a,b,a,b,a,b,a,b" + fixes.suf0);
});
}
public void OOM() {
String maxString = "*".repeat(MAX_ARRAY_LENGTH);
try {
StringJoiner sj1 = new StringJoiner("", "", "");
sj1.add(maxString);
StringJoiner sj2 = new StringJoiner("", "", "");
sj2.add(maxString);
sj1.merge(sj2);
fail("Should have thrown OutOfMemoryError");
} catch (OutOfMemoryError ex) {
// okay
}
}
}

View File

@ -24,13 +24,17 @@
* @test
* @bug 5015163 7172553
* @summary tests StringJoinerTest
* @modules java.base/jdk.internal.util
* @run testng StringJoinerTest
* @author Jim Gish
*/
import java.util.ArrayList;
import java.util.StringJoiner;
import org.testng.annotations.Test;
import static jdk.internal.util.ArraysSupport.MAX_ARRAY_LENGTH;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
@Test(groups = {"unit","string","util","libs"})
public class StringJoinerTest {
@ -320,5 +324,49 @@ public class StringJoinerTest {
testCombos(",", "", ">");
testCombos(",", "<", ">");
}
public void OOM1() {
String maxString = "*".repeat(MAX_ARRAY_LENGTH);
try {
new StringJoiner(maxString, maxString, maxString).toString();
fail("Should have thrown OutOfMemoryError");
} catch (OutOfMemoryError ex) {
// okay
}
}
public void OOM2() {
String maxString = "*".repeat(MAX_ARRAY_LENGTH);
try {
new StringJoiner(maxString, maxString, "").toString();
fail("Should have thrown OutOfMemoryError");
} catch (OutOfMemoryError ex) {
// okay
}
}
public void OOM3() {
String maxString = "*".repeat(MAX_ARRAY_LENGTH);
try {
new StringJoiner(maxString, "", maxString).toString();
fail("Should have thrown OutOfMemoryError");
} catch (OutOfMemoryError ex) {
// okay
}
}
public void OOM4() {
String maxString = "*".repeat(MAX_ARRAY_LENGTH);
try {
new StringJoiner("", maxString, maxString).toString();
fail("Should have thrown OutOfMemoryError");
} catch (OutOfMemoryError ex) {
// okay
}
}
}