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:
+ *
+ * - does not retain a reference to the {@code byte[]}
+ * - does not leak a reference to the {@code byte[]} to non-trusted classes
+ * - does not modify the contents of the {@code byte[]}
+ * - {@code write()} method does not read the contents outside of the offset/length bounds
+ *
+ *
+ * @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 extends ZipEntry> 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);
+ }
+ }
+
}