8158906: JShell: crashes with extremely long result value
Reviewed-by: jlahoda, shinyafox
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/ExecutionControlForwarder.java Fri Aug 19 12:54:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/ExecutionControlForwarder.java Fri Aug 19 13:55:26 2016 -0700
@@ -44,6 +44,13 @@
*/
class ExecutionControlForwarder {
+ /**
+ * Maximum number of characters for writeUTF(). Byte maximum is 65535, at
+ * maximum three bytes per character that is 65535 / 3 == 21845. Minus one
+ * for safety.
+ */
+ private static final int MAX_UTF_CHARS = 21844;
+
private final ExecutionControl ec;
private final ObjectInput in;
private final ObjectOutput out;
@@ -89,6 +96,9 @@
private void writeUTF(String s) throws IOException {
if (s == null) {
s = "";
+ } else if (s.length() > MAX_UTF_CHARS) {
+ // Truncate extremely long strings to prevent writeUTF from crashing the VM
+ s = s.substring(0, MAX_UTF_CHARS);
}
out.writeUTF(s);
}
--- a/langtools/test/jdk/jshell/SimpleRegressionTest.java Fri Aug 19 12:54:02 2016 -0700
+++ b/langtools/test/jdk/jshell/SimpleRegressionTest.java Fri Aug 19 13:55:26 2016 -0700
@@ -22,7 +22,7 @@
*/
/*
- * @test 8130450
+ * @test 8130450 8158906
* @summary simple regression test
* @build KullaTesting TestingInputStream
* @run testng SimpleRegressionTest
@@ -39,6 +39,8 @@
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
import static jdk.jshell.Snippet.Status.OVERWRITTEN;
import static jdk.jshell.Snippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND;
import static jdk.jshell.Snippet.Status.VALID;
@@ -100,6 +102,37 @@
assertEquals(sne.typeName(), "Integer");
}
+ public void testLongRemoteStrings() { //8158906
+ assertEval("String m(int x) { byte[] b = new byte[x]; for (int i = 0; i < x; ++i) b[i] = (byte) 'a'; return new String(b); }");
+ boolean[] shut = new boolean[1];
+ getState().onShutdown(j -> {
+ shut[0] = true;
+ });
+ for (String len : new String[]{"12345", "64000", "65535", "65536", "120000"}) {
+ List<SnippetEvent> el = assertEval("m(" + len + ");");
+ assertFalse(shut[0], "JShell died with long string");
+ assertEquals(el.size(), 1, "Excepted one event");
+ assertTrue(el.get(0).value().length() > 10000,
+ "Expected truncated but long String, got: " + el.get(0).value().length());
+ }
+ }
+
+ public void testLongRemoteJapaneseStrings() { //8158906
+ assertEval("import java.util.stream.*;");
+ assertEval("String m(int x) { return Stream.generate(() -> \"\u3042\").limit(x).collect(Collectors.joining()); }");
+ boolean[] shut = new boolean[1];
+ getState().onShutdown(j -> {
+ shut[0] = true;
+ });
+ for (String len : new String[]{"12345", "21843", "21844", "21845", "21846", "64000", "65535", "65536", "120000"}) {
+ List<SnippetEvent> el = assertEval("m(" + len + ");");
+ assertFalse(shut[0], "JShell died with long string");
+ assertEquals(el.size(), 1, "Excepted one event");
+ assertTrue(el.get(0).value().length() > 10000,
+ "Expected truncated but long String, got: " + el.get(0).value().length());
+ }
+ }
+
// 8130450
public void testDuplicate() {
Snippet snm = methodKey(assertEval("void mm() {}", added(VALID)));