diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java index a697a37141ed8..24de2af52f518 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -395,7 +395,9 @@ public synchronized void write(int b) throws IOException { buffer = Arrays.copyOf(buffer, 2 * buffer.length); } - buffer[bp++] = b; + // Can be negative because widening from byte in write(byte[], int, int). + // java.io.OutputStream.write(int b) stipulates "The 24 high-order bits of b are ignored." + buffer[bp++] = b & 0xff; switch (Task.values()[buffer[0]]) { case WRITE_CHARS -> { @@ -412,7 +414,7 @@ public synchronized void write(int b) throws IOException { } case READ_CHARS -> { if (bp >= 5) { - int len = readInt(b); + int len = readInt(1); int c = console.reader().read(); //XXX: EOF handling! sendChars(sinkOutput, new char[] {(char) c}, 0, 1); diff --git a/test/langtools/jdk/jshell/ConsoleTest.java b/test/langtools/jdk/jshell/ConsoleTest.java index 4aedc0619397f..7543453684152 100644 --- a/test/langtools/jdk/jshell/ConsoleTest.java +++ b/test/langtools/jdk/jshell/ConsoleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -157,6 +157,31 @@ public void close() throws IOException {} assertEquals(sb.toString(), expected); } + @Test + public void testConsoleUnicodeWritingTest() { + StringBuilder sb = new StringBuilder(); + console = new ThrowingJShellConsole() { + @Override + public PrintWriter writer() { + return new PrintWriter(new Writer() { + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + sb.append(cbuf, off, len); + } + @Override + public void flush() throws IOException {} + @Override + public void close() throws IOException {} + }); + } + }; + int count = 384; // 128-255, 384-511, 640-767, ... (JDK-8355371) + String testStr = "\u30A2"; // Japanese katakana (A2 >= 80) (JDK-8354910) + assertEval("System.console().writer().write(\"" + testStr + "\".repeat(" + count + "))"); + String expected = testStr.repeat(count); + assertEquals(sb.toString(), expected); + } + @Test public void testConsoleMultiThreading() { StringBuilder sb = new StringBuilder();