diff --git a/src/java.base/share/classes/java/io/BufferedInputStream.java b/src/java.base/share/classes/java/io/BufferedInputStream.java index e5a44761b8a..97d1b9677c4 100644 --- a/src/java.base/share/classes/java/io/BufferedInputStream.java +++ b/src/java.base/share/classes/java/io/BufferedInputStream.java @@ -643,9 +643,13 @@ private long implTransferTo(OutputStream out) throws IOException { if (getClass() == BufferedInputStream.class && markpos == -1) { int avail = count - pos; if (avail > 0) { - // Prevent poisoning and leaking of buf - byte[] buffer = Arrays.copyOfRange(getBufIfOpen(), pos, count); - out.write(buffer); + if (isTrusted(out)) { + out.write(getBufIfOpen(), pos, count); + } else { + // Prevent poisoning and leaking of buf + byte[] buffer = Arrays.copyOfRange(getBufIfOpen(), pos, count); + out.write(buffer); + } pos = count; } try { @@ -658,4 +662,22 @@ private long implTransferTo(OutputStream out) throws IOException { } } + /** + * Returns true if this class satisfies the following conditions: + * + * + * @return true if this class is trusted + */ + private static boolean isTrusted(OutputStream os) { + var clazz = os.getClass(); + return clazz == ByteArrayOutputStream.class + || clazz == FileOutputStream.class + || clazz == PipedOutputStream.class; + } + } diff --git a/src/java.base/share/classes/java/util/IdentityHashMap.java b/src/java.base/share/classes/java/util/IdentityHashMap.java index 77f06fb9410..f1f4b802b5f 100644 --- a/src/java.base/share/classes/java/util/IdentityHashMap.java +++ b/src/java.base/share/classes/java/util/IdentityHashMap.java @@ -267,7 +267,7 @@ private void init(int initCapacity) { } /** - * Constructs a new identity hash map containing the keys-value mappings + * Constructs a new identity hash map containing the key-value mappings * in the specified map. * * @param m the map whose mappings are to be placed into this map diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java index 67bdaa481d3..9b6c7d7ad4c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 @@ -189,45 +189,73 @@ public BootstrapMethodEntryImpl bootstrapMethodEntry(int index) { return bsmEntries().get(index); } + private static IllegalArgumentException outOfBoundsError(IndexOutOfBoundsException cause) { + return new IllegalArgumentException("Reading beyond classfile bounds", cause); + } + @Override public int readU1(int p) { - return buffer[p] & 0xFF; + try { + return buffer[p] & 0xFF; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } } @Override public int readU2(int p) { - int b1 = buffer[p] & 0xFF; - int b2 = buffer[p + 1] & 0xFF; - return (b1 << 8) + b2; + try { + int b1 = buffer[p] & 0xFF; + int b2 = buffer[p + 1] & 0xFF; + return (b1 << 8) + b2; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } } @Override public int readS1(int p) { - return buffer[p]; + try { + return buffer[p]; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } } @Override public int readS2(int p) { - int b1 = buffer[p]; - int b2 = buffer[p + 1] & 0xFF; - return (b1 << 8) + b2; + try { + int b1 = buffer[p]; + int b2 = buffer[p + 1] & 0xFF; + return (b1 << 8) + b2; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } } @Override public int readInt(int p) { - int ch1 = buffer[p] & 0xFF; - int ch2 = buffer[p + 1] & 0xFF; - int ch3 = buffer[p + 2] & 0xFF; - int ch4 = buffer[p + 3] & 0xFF; - return (ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4; + try { + int ch1 = buffer[p] & 0xFF; + int ch2 = buffer[p + 1] & 0xFF; + int ch3 = buffer[p + 2] & 0xFF; + int ch4 = buffer[p + 3] & 0xFF; + return (ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } } @Override public long readLong(int p) { - return ((long) buffer[p + 0] << 56) + ((long) (buffer[p + 1] & 255) << 48) + - ((long) (buffer[p + 2] & 255) << 40) + ((long) (buffer[p + 3] & 255) << 32) + - ((long) (buffer[p + 4] & 255) << 24) + ((buffer[p + 5] & 255) << 16) + ((buffer[p + 6] & 255) << 8) + - (buffer[p + 7] & 255); + try { + return ((long) buffer[p + 0] << 56) + ((long) (buffer[p + 1] & 255) << 48) + + ((long) (buffer[p + 2] & 255) << 40) + ((long) (buffer[p + 3] & 255) << 32) + + ((long) (buffer[p + 4] & 255) << 24) + ((buffer[p + 5] & 255) << 16) + ((buffer[p + 6] & 255) << 8) + + (buffer[p + 7] & 255); + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } } @Override @@ -242,12 +270,20 @@ public double readDouble(int p) { @Override public byte[] readBytes(int p, int len) { - return Arrays.copyOfRange(buffer, p, p + len); + try { + return Arrays.copyOfRange(buffer, p, p + len); + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } } @Override public void copyBytesTo(BufWriter buf, int p, int len) { - buf.writeBytes(buffer, p, len); + try { + buf.writeBytes(buffer, p, len); + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } } BootstrapMethodsAttribute bootstrapMethodsAttribute() { @@ -446,8 +482,12 @@ public boolean compare(BufWriter bufWriter, int bufWriterOffset, int classReaderOffset, int length) { - return Arrays.equals(((BufWriterImpl) bufWriter).elems, - bufWriterOffset, bufWriterOffset + length, - buffer, classReaderOffset, classReaderOffset + length); + try { + return Arrays.equals(((BufWriterImpl) bufWriter).elems, + bufWriterOffset, bufWriterOffset + length, + buffer, classReaderOffset, classReaderOffset + length); + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java index fd1e612997a..f3efffb5b56 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 @@ -44,49 +44,64 @@ public SignaturesImpl() { public ClassSignature parseClassSignature(String signature) { this.sig = signature; sigp = 0; - List typeParamTypes = parseParamTypes(); - RefTypeSig superclass = referenceTypeSig(); - ArrayList superinterfaces = null; - while (sigp < sig.length()) { - if (superinterfaces == null) - superinterfaces = new ArrayList<>(); - superinterfaces.add(referenceTypeSig()); + try { + List typeParamTypes = parseParamTypes(); + RefTypeSig superclass = referenceTypeSig(); + ArrayList superinterfaces = null; + while (sigp < sig.length()) { + if (superinterfaces == null) + superinterfaces = new ArrayList<>(); + superinterfaces.add(referenceTypeSig()); + } + return new ClassSignatureImpl(typeParamTypes, superclass, null2Empty(superinterfaces)); + } catch (IndexOutOfBoundsException e) { + throw error("Not a valid class signature"); } - return new ClassSignatureImpl(typeParamTypes, superclass, null2Empty(superinterfaces)); } public MethodSignature parseMethodSignature(String signature) { this.sig = signature; sigp = 0; - List typeParamTypes = parseParamTypes(); - assert sig.charAt(sigp) == '('; - sigp++; - ArrayList paramTypes = null; - while (sig.charAt(sigp) != ')') { - if (paramTypes == null) - paramTypes = new ArrayList<>(); - paramTypes.add(typeSig()); - } - sigp++; - Signature returnType = typeSig(); - ArrayList throwsTypes = null; - while (sigp < sig.length() && sig.charAt(sigp) == '^') { + try { + List typeParamTypes = parseParamTypes(); + if (sig.charAt(sigp) != '(') throw error("Expected ( at possition %d of signature".formatted(sigp)); + sigp++; + ArrayList paramTypes = null; + while (sig.charAt(sigp) != ')') { + if (paramTypes == null) + paramTypes = new ArrayList<>(); + paramTypes.add(typeSig()); + } sigp++; - if (throwsTypes == null) - throwsTypes = new ArrayList<>(); - var t = typeSig(); - if (t instanceof ThrowableSig ts) - throwsTypes.add(ts); - else - throw new IllegalArgumentException("not a valid type signature: " + sig); + Signature returnType = typeSig(); + ArrayList throwsTypes = null; + while (sigp < sig.length()) { + if (sig.charAt(sigp) != '^') throw error("Expected ^ at possition %d of signature".formatted(sigp)); + sigp++; + if (throwsTypes == null) + throwsTypes = new ArrayList<>(); + var t = referenceTypeSig(); + if (t instanceof ThrowableSig ts) + throwsTypes.add(ts); + else + throw error("Not a valid throwable signature %s in".formatted(t.signatureString())); + } + return new MethodSignatureImpl(typeParamTypes, null2Empty(throwsTypes), returnType, null2Empty(paramTypes)); + } catch (IndexOutOfBoundsException e) { + throw error("Not a valid method signature"); } - return new MethodSignatureImpl(typeParamTypes, null2Empty(throwsTypes), returnType, null2Empty(paramTypes)); } public Signature parseSignature(String signature) { this.sig = signature; sigp = 0; - return typeSig(); + try { + var s = typeSig(); + if (sigp == signature.length()) + return s; + } catch (IndexOutOfBoundsException e) { + } + throw error("Not a valid type signature"); } private List parseParamTypes() { @@ -157,7 +172,7 @@ private RefTypeSig referenceTypeSig() { return ty; case '[': return ArrayTypeSig.of(typeSig()); } - throw new IllegalArgumentException("not a valid type signature: " + sig); + throw error("Unexpected character %c at possition %d of signature".formatted(c, sigp - 1)); } private TypeArg typeArg() { @@ -292,4 +307,8 @@ public String signatureString() { private static List null2Empty(ArrayList l) { return l == null ? List.of() : Collections.unmodifiableList(l); } + + private IllegalArgumentException error(String message) { + return new IllegalArgumentException("%s: %s".formatted(message, sig)); + } } diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java index 0dfd86caf1a..88c74322c39 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -169,7 +169,7 @@ private ElementFilter() {} // Do not instantiate. } /** - * {@return a set of types in {@code elements}} + * {@return a set of classes and interfaces in {@code elements}} * @param elements the elements to filter */ public static Set diff --git a/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java b/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java index 2cee1fc2489..47ef2e437c9 100644 --- a/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java +++ b/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java @@ -95,7 +95,7 @@ public XMLStreamException(String msg, Throwable th) { public XMLStreamException(String msg, Location location, Throwable th) { super("ParseError at [row,col]:["+location.getLineNumber()+","+ location.getColumnNumber()+"]\n"+ - "Message: "+msg); + "Message: "+msg, th); nested = th; this.location = location; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java index 0dd32fd8eca..f6ce19fac06 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java @@ -506,7 +506,7 @@ public void visitMethodDef(JCMethodDecl tree) { public void visitApply(JCMethodInvocation invoke) { // Get method symbol - MethodSymbol sym = (MethodSymbol)TreeInfo.symbolFor(invoke.meth); + Symbol sym = TreeInfo.symbolFor(invoke.meth); // Recurse on method expression scan(invoke.meth); @@ -530,7 +530,7 @@ public void visitApply(JCMethodInvocation invoke) { invoke(invoke, sym, invoke.args, receiverRefs); } - private void invoke(JCTree site, MethodSymbol sym, List args, RefSet receiverRefs) { + private void invoke(JCTree site, Symbol sym, List args, RefSet receiverRefs) { // Skip if ignoring warnings for a constructor invoked via 'this()' if (suppressed.contains(sym)) @@ -810,6 +810,10 @@ public void visitSelect(JCFieldAccess tree) { @Override public void visitReference(JCMemberReference tree) { + if (tree.type.isErroneous()) { + //error recovery - ignore erroneous member references + return ; + } // Scan target expression and extract 'this' references, if any scan(tree.expr); diff --git a/test/jaxp/javax/xml/jaxp/unittest/stream/XMLStreamExceptionTest/ExceptionCauseTest.java b/test/jaxp/javax/xml/jaxp/unittest/stream/XMLStreamExceptionTest/ExceptionCauseTest.java new file mode 100644 index 00000000000..e32527621f8 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/stream/XMLStreamExceptionTest/ExceptionCauseTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023, 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. + */ + +package stream.XMLStreamExceptionTest; + +import java.io.IOException; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; + +import org.testng.Assert; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +/* + * @test + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng/othervm -DrunSecMngr=true -Djava.security.manager=allow stream.XMLStreamExceptionTest.ExceptionCauseTest + * @run testng/othervm stream.XMLStreamExceptionTest.ExceptionCauseTest + * @summary Test XMLStreamException constructor initializes chained exception + */ +@Listeners({jaxp.library.BasePolicy.class}) +public class ExceptionCauseTest { + + @Test + public void testExceptionCause() { + + // Create exception with cause + Throwable cause = new Throwable("cause"); + Location location = new Location() { + public int getLineNumber() { return 0; } + public int getColumnNumber() { return 0; } + public int getCharacterOffset() { return 0; } + public String getPublicId() { return null; } + public String getSystemId() { return null; } + }; + XMLStreamException e = new XMLStreamException("message", location, cause); + + // Verify cause + Assert.assertSame(e.getCause(), cause, "XMLStreamException has the wrong cause"); + } +} diff --git a/test/jdk/java/io/BufferedInputStream/TransferToTrusted.java b/test/jdk/java/io/BufferedInputStream/TransferToTrusted.java new file mode 100644 index 00000000000..c0bd7b53af8 --- /dev/null +++ b/test/jdk/java/io/BufferedInputStream/TransferToTrusted.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023, 2024, 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. + */ + +import java.io.*; +import java.util.Arrays; +import java.util.Objects; +import java.util.Random; + +/* + * @test + * @bug 8320971 + * @summary Verify BufferedInputStream.buf is used directly by + * BufferedInputStream.implTransferTo() only when its OutputStream + * parameter is trusted + * @key randomness + * @run main/othervm --add-opens=java.base/java.io=ALL-UNNAMED TransferToTrusted + */ +public class TransferToTrusted { + + private static final Random RND = new Random(System.nanoTime()); + + private static final class UntrustedOutputStream extends OutputStream { + + UntrustedOutputStream() { + super(); + } + + @Override + public void write(byte[] b, int off, int len) { + Objects.checkFromIndexSize(off, len, b.length); + byte[] tmp = new byte[len]; + RND.nextBytes(tmp); + System.arraycopy(tmp, 0, b, off, len); + } + + @Override + public void write(int b) throws IOException { + write(new byte[]{(byte) b}); + } + } + + public static void main(String[] args) throws Exception { + final int length = 128; + byte[] buf = new byte[length]; + RND.nextBytes(buf); + + var outputStreams = new OutputStream[]{ + new ByteArrayOutputStream(), + new FileOutputStream(File.createTempFile(TransferToTrusted.class.getName(), null)), + new PipedOutputStream(new PipedInputStream(length)), + new UntrustedOutputStream() + }; + + for (var out : outputStreams) { + System.err.println("out: " + out.getClass().getName()); + + var bis = new BufferedInputStream(new ByteArrayInputStream(buf.clone())); + try (out; bis) { + bis.read();//need this to fill the BIS.buf in + bis.transferTo(out); + var internalBuffer = bis.getClass().getDeclaredField("buf"); + internalBuffer.setAccessible(true); + if (!Arrays.equals(buf, Arrays.copyOf((byte[]) internalBuffer.get(bis), length))) { + throw new RuntimeException("Internal buffer was modified"); + } + } + } + } +} diff --git a/test/jdk/java/util/zip/ZipCoding.java b/test/jdk/java/util/zip/ZipCoding.java index 852522b9a6a..14a0e96f174 100644 --- a/test/jdk/java/util/zip/ZipCoding.java +++ b/test/jdk/java/util/zip/ZipCoding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, 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,111 +23,185 @@ /** * @test - * @bug 4244499 4532049 4700978 4820807 4980042 + * @bug 4244499 4532049 4700978 4820807 4980042 7009069 8322802 * @summary Test ZipInputStream, ZipOutputStream and ZipFile with non-UTF8 encoding * @modules jdk.charsets + * @run junit ZipCoding */ +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import java.io.*; import java.nio.charset.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; +import java.util.stream.Stream; import java.util.zip.*; +import static org.junit.jupiter.api.Assertions.*; + public class ZipCoding { - public static void main(String[] args) throws Exception { + // The data to write to ZIP entries in this test + private static byte[] ENTRY_DATA = "German Umlaut \u00fc in entry data" + .getBytes(StandardCharsets.ISO_8859_1); + + /** + * Provide arguments used for parameterized tests + * @return a stream of argument lists + */ + public static Stream charsetsAndNames() { + // Arguments are: Write charset, read charset, entry name, comment + return Stream.of( + // MS code page 932 for the Japanese language + Arguments.of("MS932", "MS932", + "\u4e00\u4e01", + "\uff67\uff68\uff69\uff6a\uff6b\uff6c"), - test("MS932", - "\u4e00\u4e01", "\uff67\uff68\uff69\uff6a\uff6b\uff6c"); + // Code page for the IBM PC + Arguments.of("ibm437", "ibm437", + "\u00e4\u00fc", + "German Umlaut \u00fc in comment"), - test("ibm437", - "\u00e4\u00fc", "German Umlaut \u00fc in comment"); + // UTF-8 with Japanese characters + Arguments.of("utf-8", "utf-8", + "\u4e00\u4e01", + "\uff67\uff68\uff69\uff6a\uff6b\uff6c"), - test("utf-8", - "\u4e00\u4e01", "\uff67\uff68\uff69\uff6a\uff6b\uff6c"); + // UTF-8 with characters in the Latin1 range + Arguments.of("utf-8", "utf-8", + "\u00e4\u00fc", + "German Umlaut \u00fc in comment"), - test("utf-8", - "\u00e4\u00fc", "German Umlaut \u00fc in comment"); + // UTF-8 with surrogate pairs + Arguments.of("utf-8", "utf-8", + "Surrogate\ud801\udc01", + "Surrogates \ud800\udc00 in comment"), - test("utf-8", - "Surrogate\ud801\udc01", "Surrogates \ud800\udc00 in comment"); + // ZipOutputStream sets the 'Language encoding flag' when writing using UTF-8 + // UTF-8 should be used for decoding, regardless of the opening charset + // UTF-8 with Japanese characters, opened with MS932 + Arguments.of("utf-8", "MS932", + "\u4e00\u4e01", + "\uff67\uff68\uff69\uff6a\uff6b\uff6c"), + + // UTF-8 with characters in latin1 range, opened with iso-8859-1 + Arguments.of("utf-8", "iso-8859-1", + "\u00e4\u00fc", + "German Umlaut \u00fc in comment"), + // UTF-8 with surrogate pairs, opened with MS932 + Arguments.of("utf-8", "MS932", + "Surrogate\ud801\udc01", + "Surrogates \ud800\udc00 in comment") + ); } - static void testZipInputStream(InputStream is, Charset cs, - String name, String comment, byte[] bb) - throws Exception - { - try (ZipInputStream zis = new ZipInputStream(is, cs)) { + /** + * Verify that ZipInputStream decodes entry names and comments + * using the charset provided to its constructor, or that it decodes + * using UTF-8 when the 'Language encoding flag' is set + * + * @param writeCharset the charset to use for ZipOutputStream when producing the ZIP + * @param readCharset the charset to use when opening the ZipInputStream + * @param name the entry name + * @param comment the entry comment (not read by ZipInputStream) + * + * @throws IOException if an unexpected IOException occurs + */ + @ParameterizedTest + @MethodSource("charsetsAndNames") + public void testZipInputStream(String writeCharset, + String readCharset, + String name, + String comment) throws IOException { + + byte[] zip = createZIP(writeCharset, name, comment); + + try (InputStream in = new ByteArrayInputStream(zip); + ZipInputStream zis = new ZipInputStream(in, Charset.forName(readCharset))) { ZipEntry e = zis.getNextEntry(); - if (e == null || ! name.equals(e.getName())) - throw new RuntimeException("ZipIS name doesn't match!"); - byte[] bBuf = new byte[bb.length << 1]; - int n = zis.read(bBuf, 0, bBuf.length); - if (n != bb.length || - !Arrays.equals(bb, Arrays.copyOf(bBuf, n))) { - throw new RuntimeException("ZipIS content doesn't match!"); - } + assertNotNull(e); + assertEquals(name, e.getName(), + "ZipInputStream.getNextEntry() returned unexpected entry name"); + assertNull(e.getComment()); // No comment in the LOC header + assertArrayEquals(ENTRY_DATA, zis.readAllBytes(), "Unexpected ZIP entry data"); } } - static void testZipFile(File f, Charset cs, - String name, String comment, byte[] bb) - throws Exception - { - try (ZipFile zf = new ZipFile(f, cs)) { + /** + * Verify that ZipFile decodes entry names and comments + * using the charset provided to its constructor, or that it decodes + * using UTF-8 when the 'Language encoding flag' is set + * + * @param writeCharset the charset to use for ZipOutputStream when producing the ZIP + * @param readCharset the charset to use when opening the ZipFile + * @param name the name of the entry + * @param comment the comment of the entry + * + * @throws IOException if an unexpected IOException occurs + */ + @ParameterizedTest + @MethodSource("charsetsAndNames") + public void testZipFile(String writeCharset, + String readCharset, + String name, + String comment) throws IOException { + + byte[] zip = createZIP(writeCharset, name, comment); + + Path f = Path.of("zfcoding.zip"); + Files.write(f, zip); + + try (ZipFile zf = new ZipFile(f.toFile(), Charset.forName(readCharset))) { + // Test using ZipFile.entries Enumeration zes = zf.entries(); ZipEntry e = (ZipEntry)zes.nextElement(); - if (! name.equals(e.getName()) || - ! comment.equals(e.getComment())) - throw new RuntimeException("ZipFile: name/comment doesn't match!"); - InputStream is = zf.getInputStream(e); - if (is == null) - throw new RuntimeException("ZipFile: getIS failed!"); - byte[] bBuf = new byte[bb.length << 1]; - int n = 0; - int nn =0; - while ((nn = is.read(bBuf, n, bBuf.length-n)) != -1) { - n += nn; - } - if (n != bb.length || - !Arrays.equals(bb, Arrays.copyOf(bBuf, n))) { - throw new RuntimeException("ZipFile content doesn't match!"); + assertNotNull(e); + assertEquals(name, e.getName(), "ZipFile.entries() returned unexpected entry name"); + assertEquals(comment, e.getComment(), "ZipFile.entries() returned unexpected entry comment"); + + // Test using ZipFile.getEntry + e = zf.getEntry(name); + assertNotNull(e, + String.format("Entry lookup failed on ZIP encoded with %s and opened with %s", + writeCharset, readCharset)); + assertEquals(name, e.getName(), "ZipFile.getEntry() returned unexpected entry name"); + assertEquals(comment, e.getComment(), "ZipFile.getEntry() returned unexpected entry comment"); + try (InputStream is = zf.getInputStream(e)) { + assertNotNull(is); + assertArrayEquals(ENTRY_DATA, is.readAllBytes(), "Unexpected ZIP entry data"); } } + + Files.deleteIfExists(f); } - static void test(String csn, String name, String comment) - throws Exception - { - byte[] bb = "This is the content of the zipfile".getBytes("ISO-8859-1"); - Charset cs = Charset.forName(csn); + /** + * Create a ZIP file containing an entry with the given name + * and comment, encoded using the given charset. + * Note that if the charset is UTF-8, ZipOutputStream will + * set the 'Language encoding flag' for the entry. + * + * @param charset the charset passed to the ZipOutputStream constructor + * @param name the name of the entry to add + * @param comment the comment of the entry to add + * @return a byte array containing the ZIP file + * + * @throws IOException if an unexpected IOException occurs + */ + private byte[] createZIP(String charset, String name, String comment) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (ZipOutputStream zos = new ZipOutputStream(baos, cs)) { + try (ZipOutputStream zos = new ZipOutputStream(baos, Charset.forName(charset))) { ZipEntry e = new ZipEntry(name); e.setComment(comment); zos.putNextEntry(e); - zos.write(bb, 0, bb.length); + zos.write(ENTRY_DATA); zos.closeEntry(); } - ByteArrayInputStream bis = new ByteArrayInputStream(baos.toByteArray()); - testZipInputStream(bis, cs, name, comment, bb); - - if ("utf-8".equals(csn)) { - // USE_UTF8 should be set - bis.reset(); - testZipInputStream(bis, Charset.forName("MS932"), name, comment, bb); - } - - File f = new File(new File(System.getProperty("test.dir", ".")), - "zfcoding.zip"); - try (FileOutputStream fos = new FileOutputStream(f)) { - baos.writeTo(fos); - } - testZipFile(f, cs, name, comment, bb); - if ("utf-8".equals(csn)) { - testZipFile(f, Charset.forName("MS932"), name, comment, bb); - } - f.delete(); + return baos.toByteArray(); } } diff --git a/test/jdk/javax/swing/AbstractButton/5049549/DE1.gif b/test/jdk/javax/swing/AbstractButton/5049549/DE1.gif deleted file mode 100644 index 3c12953f9a5..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/DE1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/DI1.gif b/test/jdk/javax/swing/AbstractButton/5049549/DI1.gif deleted file mode 100644 index a812a358b9d..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/DI1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/DS1.gif b/test/jdk/javax/swing/AbstractButton/5049549/DS1.gif deleted file mode 100644 index 5559452e839..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/DS1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/PR1.gif b/test/jdk/javax/swing/AbstractButton/5049549/PR1.gif deleted file mode 100644 index adefa4459d8..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/PR1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/RO1.gif b/test/jdk/javax/swing/AbstractButton/5049549/RO1.gif deleted file mode 100644 index 68bcf8bed1f..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/RO1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/RS1.gif b/test/jdk/javax/swing/AbstractButton/5049549/RS1.gif deleted file mode 100644 index 09e183eb531..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/RS1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/SE1.gif b/test/jdk/javax/swing/AbstractButton/5049549/SE1.gif deleted file mode 100644 index d408843b337..00000000000 Binary files a/test/jdk/javax/swing/AbstractButton/5049549/SE1.gif and /dev/null differ diff --git a/test/jdk/javax/swing/AbstractButton/5049549/bug5049549.java b/test/jdk/javax/swing/AbstractButton/5049549/bug5049549.java index fd03f6e918d..c24435eb18c 100644 --- a/test/jdk/javax/swing/AbstractButton/5049549/bug5049549.java +++ b/test/jdk/javax/swing/AbstractButton/5049549/bug5049549.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2023, 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 @@ -21,14 +21,10 @@ * questions. */ -/* @test - @bug 5049549 7132413 - @summary Tests that the proper icon is used for different states. - @library ../../regtesthelpers - @build Blocker - @run main/manual bug5049549 -*/ - +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.image.BufferedImage; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; @@ -39,17 +35,39 @@ import javax.swing.SwingUtilities; import javax.swing.UIManager; +/* + * @test + * @bug 5049549 7132413 + * @summary Tests that the proper icon is used for different states. + * @library ../../regtesthelpers + * @build Blocker + * @run main/manual bug5049549 + */ public class bug5049549 { - private static ImageIcon DE = new ImageIcon(bug5049549.class.getResource("DE1.gif")); - private static ImageIcon DI = new ImageIcon(bug5049549.class.getResource("DI1.gif")); - private static ImageIcon DS = new ImageIcon(bug5049549.class.getResource("DS1.gif")); - private static ImageIcon RO = new ImageIcon(bug5049549.class.getResource("RO1.gif")); - private static ImageIcon RS = new ImageIcon(bug5049549.class.getResource("RS1.gif")); - private static ImageIcon SE = new ImageIcon(bug5049549.class.getResource("SE1.gif")); - private static ImageIcon PR = new ImageIcon(bug5049549.class.getResource("PR1.gif")); - - private static Blocker blocker = new Blocker(); + private static final Icon DE = generateImage("DE"); + private static final Icon DI = generateImage("DI"); + private static final Icon DS = generateImage("DS"); + private static final Icon RO = generateImage("RO"); + private static final Icon RS = generateImage("RS"); + private static final Icon SE = generateImage("SE"); + private static final Icon PR = generateImage("PR"); + + private static final Blocker blocker = new Blocker(); + + private static Icon generateImage(String str) { + BufferedImage img = new BufferedImage(40, 30, + BufferedImage.TYPE_INT_RGB); + Graphics g = img.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, img.getWidth(), img.getHeight()); + g.setColor(Color.RED); + Font font = new Font(Font.SANS_SERIF, Font.BOLD, 22); + g.setFont(font); + g.drawString(str, 5, 25); + g.dispose(); + return new ImageIcon(img); + } private static class KButton extends JButton { diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index b89a312a67f..d23a948fe9f 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,6 +23,7 @@ /* * @test + * @bug 8320360 * @summary Testing ClassFile limits. * @run junit LimitsTest */ @@ -85,4 +86,10 @@ void testSupportedClassVersion() { var cf = ClassFile.of(); assertThrows(IllegalArgumentException.class, () -> cf.parse(cf.build(ClassDesc.of("ClassFromFuture"), cb -> cb.withVersion(ClassFile.latestMajorVersion() + 1, 0)))); } + + @Test + void testReadingOutOfBounds() { + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE}), "reading magic only"); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, 0, 0, 0, 0, 0, 2}), "reading invalid CP size"); + } } diff --git a/test/jdk/jdk/classfile/SignaturesTest.java b/test/jdk/jdk/classfile/SignaturesTest.java index 9f5fbe8adca..2c64bacee41 100644 --- a/test/jdk/jdk/classfile/SignaturesTest.java +++ b/test/jdk/jdk/classfile/SignaturesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 @@ -24,6 +24,7 @@ /* * @test * @summary Testing Signatures. + * @bug 8321540 * @run junit SignaturesTest */ import java.io.IOException; @@ -46,8 +47,11 @@ import java.lang.classfile.Attributes; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Assertions; import static helpers.ClassRecord.assertEqualsDeep; import static java.lang.constant.ConstantDescs.*; +import java.util.function.Consumer; +import java.util.function.Function; class SignaturesTest { @@ -186,4 +190,79 @@ void testClassSignatureClassDesc() throws IOException { assertEquals(Outer.Inner.class.describeConstable().orElseThrow(), innerSig.classDesc(), "ClassDesc derived from signature"); } + + @Test + void testBadTypeSignatures() { + """ + LObject + LObject;B + LIterable + LIterable<< + TBar + TBar + B + B;V + X + [LObject + [LIterable + [LIterable<< + [TBar + [TBar + [B + [X + LSet<+Kind<**>;>; + LSet;>; + ()V + """.lines().forEach(assertThrows(Signature::parseFrom)); + } + + @Test + void testBadClassSignatures() { + """ + Ljava/lang/Object;Ljava/lang/Iterable + LObject + LObject;B + LIterable + LIterable<< + TBar + TBar + B + B;V + X + LFoo.It;L + LFoo;LFoo;LBar; + >LFoo; + LFoo<+>; + ()V + """.lines().forEach(assertThrows(ClassSignature::parseFrom)); + } + + @Test + void testBadMethodSignatures() { + """ + LObject; + B + ()V^ + ()V^B + ()V^X + (LObject;) + (LObject)V + ()LIterable + ()LIterable<< + ()TBar + ()TBar;B + (TBar)V + (B)V + (X) + ()X + ()VB + ()LSet<+Kind<**>;>; + (LSet;>;)V + ()V + """.lines().forEach(assertThrows(MethodSignature::parseFrom)); + } + + private Consumer assertThrows(Function parser) { + return s -> Assertions.assertThrows(IllegalArgumentException.class, () -> parser.apply(s), s); + } } diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index 607575b291f..2ab92a625d0 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 + * @bug 8301580 8322159 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @enablePreview @@ -87,4 +87,41 @@ class C { } } + @Test + public void testX() throws Exception { + String code = """ + public class C { + public C() { + Undefined.method(); + undefined1(); + Runnable r = this::undefined2; + overridable(this); //to verify ThisEscapeAnalyzer has been run + } + public void overridable(C c) {} + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev", + "-XDshould-stop.at=FLOW", "-Xlint:this-escape") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "C.java:3:9: compiler.err.cant.resolve.location: kindname.variable, Undefined, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:4:9: compiler.err.cant.resolve.location.args: kindname.method, undefined1, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:5:22: compiler.err.invalid.mref: kindname.method, (compiler.misc.cant.resolve.location.args: kindname.method, undefined2, , , (compiler.misc.location: kindname.class, C, null))", + "C.java:6:20: compiler.warn.possible.this.escape", + "3 errors", + "1 warning" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + }