This commit is contained in:
Jesper Wilhelmsson 2021-07-22 00:46:18 +00:00
commit c36755dedf
33 changed files with 483 additions and 114 deletions

View file

@ -1001,7 +1001,7 @@ void RangeCheckEliminator::calc_bounds(BlockBegin *block, BlockBegin *loop_heade
} else {
// Has no upper bound
Instruction *instr = ai->length();
if (instr != NULL) instr = ai->array();
if (instr == NULL) instr = ai->array();
update_bound(pushed, ai->index(), Instruction::lss, instr, 0);
}
}

View file

@ -1237,9 +1237,9 @@ class ConcreteMethodFinder : public AbstractClassHierarchyWalker {
virtual Klass* find_witness_in(KlassDepChange& changes);
virtual Klass* find_witness_anywhere(InstanceKlass* context_type);
public:
bool witnessed_reabstraction_in_supers(Klass* k);
public:
ConcreteMethodFinder(Method* m, Klass* participant = NULL) : AbstractClassHierarchyWalker(participant) {
assert(m != NULL && m->is_method(), "sanity");
_name = m->name();
@ -1752,19 +1752,89 @@ Klass* Dependencies::find_unique_concrete_subtype(InstanceKlass* ctxk) {
}
}
// Try to determine whether root method in some context is concrete or not based on the information about the unique method
// in that context. It exploits the fact that concrete root method is always inherited into the context when there's a unique method.
// Hence, unique method holder is always a supertype of the context class when root method is concrete.
// Examples for concrete_root_method
// C (C.m uniqm)
// |
// CX (ctxk) uniqm is inherited into context.
//
// CX (ctxk) (CX.m uniqm) here uniqm is defined in ctxk.
// Examples for !concrete_root_method
// CX (ctxk)
// |
// C (C.m uniqm) uniqm is in subtype of ctxk.
bool Dependencies::is_concrete_root_method(Method* uniqm, InstanceKlass* ctxk) {
if (uniqm == NULL) {
return false; // match Dependencies::is_concrete_method() behavior
}
// Theoretically, the "direction" of subtype check matters here.
// On one hand, in case of interface context with a single implementor, uniqm can be in a superclass of the implementor which
// is not related to context class.
// On another hand, uniqm could come from an interface unrelated to the context class, but right now it is not possible:
// it is required that uniqm->method_holder() is the participant (uniqm->method_holder() <: ctxk), hence a default method
// can't be used as unique.
if (ctxk->is_interface()) {
InstanceKlass* implementor = ctxk->implementor();
assert(implementor != ctxk, "single implementor only"); // should have been invalidated earlier
ctxk = implementor;
}
InstanceKlass* holder = uniqm->method_holder();
assert(!holder->is_interface(), "no default methods allowed");
assert(ctxk->is_subclass_of(holder) || holder->is_subclass_of(ctxk), "not related");
return ctxk->is_subclass_of(holder);
}
// If a class (or interface) has a unique concrete method uniqm, return NULL.
// Otherwise, return a class that contains an interfering method.
Klass* Dependencies::check_unique_concrete_method(InstanceKlass* ctxk,
Method* uniqm,
NewKlassDepChange* changes) {
// Here is a missing optimization: If uniqm->is_final(),
// we don't really need to search beneath it for overrides.
// This is probably not important, since we don't use dependencies
// to track final methods. (They can't be "definalized".)
ConcreteMethodFinder wf(uniqm, uniqm->method_holder());
Klass* k = wf.find_witness(ctxk, changes);
if (k != NULL) {
return k;
}
if (!Dependencies::is_concrete_root_method(uniqm, ctxk) || changes != NULL) {
Klass* conck = find_witness_AME(ctxk, uniqm, changes);
if (conck != NULL) {
// Found a concrete subtype 'conck' which does not override abstract root method.
return conck;
}
}
return NULL;
}
// Search for AME.
// There are two version of checks.
// 1) Spot checking version(Classload time). Newly added class is checked for AME.
// Checks whether abstract/overpass method is inherited into/declared in newly added concrete class.
// 2) Compile time analysis for abstract/overpass(abstract klass) root_m. The non uniqm subtrees are checked for concrete classes.
Klass* Dependencies::find_witness_AME(InstanceKlass* ctxk, Method* m, KlassDepChange* changes) {
if (m != NULL) {
if (changes != NULL) {
// Spot checking version.
ConcreteMethodFinder wf(m);
Klass* new_type = changes->as_new_klass_change()->new_type();
if (wf.witnessed_reabstraction_in_supers(new_type)) {
return new_type;
}
} else {
// Note: It is required that uniqm->method_holder() is the participant (see ClassHierarchyWalker::found_method()).
ConcreteSubtypeFinder wf(m->method_holder());
Klass* conck = wf.find_witness(ctxk);
if (conck != NULL) {
Method* cm = InstanceKlass::cast(conck)->find_instance_method(m->name(), m->signature(), Klass::PrivateLookupMode::skip);
if (!Dependencies::is_concrete_method(cm, conck)) {
return conck;
}
}
}
}
return NULL;
}
// Find the set of all non-abstract methods under ctxk that match m.
// (The method m must be defined or inherited in ctxk.)
@ -1787,6 +1857,9 @@ Method* Dependencies::find_unique_concrete_method(InstanceKlass* ctxk, Method* m
if (participant != NULL) {
(*participant) = wf.participant(0);
}
if (!Dependencies::is_concrete_method(fm, NULL)) {
fm = NULL; // ignore abstract methods
}
if (Dependencies::is_concrete_method(m, ctxk)) {
if (fm == NULL) {
// It turns out that m was always the only implementation.
@ -1796,7 +1869,11 @@ Method* Dependencies::find_unique_concrete_method(InstanceKlass* ctxk, Method* m
// (This can happen if m is inherited into ctxk and fm overrides it.)
return NULL;
}
} else if (Dependencies::find_witness_AME(ctxk, fm) != NULL) {
// Found a concrete subtype which does not override abstract root method.
return NULL;
}
assert(Dependencies::is_concrete_root_method(fm, ctxk) == Dependencies::is_concrete_method(m, ctxk), "mismatch");
#ifndef PRODUCT
// Make sure the dependency mechanism will pass this discovery:
if (VerifyDependencies && fm != NULL) {

View file

@ -384,6 +384,9 @@ class Dependencies: public ResourceObj {
static bool is_concrete_method(Method* m, Klass* k); // m is invocable
static Klass* find_finalizable_subclass(InstanceKlass* ik);
static bool is_concrete_root_method(Method* uniqm, InstanceKlass* ctxk);
static Klass* find_witness_AME(InstanceKlass* ctxk, Method* m, KlassDepChange* changes = NULL);
// These versions of the concreteness queries work through the CI.
// The CI versions are allowed to skew sometimes from the VM
// (oop-based) versions. The cost of such a difference is a

View file

@ -458,10 +458,6 @@ C2V_VMENTRY_NULL(jobject, findUniqueConcreteMethod, (JNIEnv* env, jobject, jobje
JVMCI_THROW_MSG_NULL(InternalError, err_msg("Effectively static method %s.%s should be handled in Java code", method->method_holder()->external_name(), method->external_name()));
}
if (method->is_abstract()) {
return NULL;
}
methodHandle ucm;
{
MutexLocker locker(Compile_lock);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2021, 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
@ -151,7 +151,7 @@ class NTLM {
int readShort(int offset) throws NTLMException {
try {
return (internal[offset] & 0xff) +
((internal[offset+1] & 0xff << 8));
(((internal[offset+1] & 0xff) << 8));
} catch (ArrayIndexOutOfBoundsException ex) {
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
"Input message incorrect size");

View file

@ -430,7 +430,10 @@ public final class ZoneRules implements Serializable {
}
/**
* Reads the state from the stream.
* Reads the state from the stream. The 1,024 limit to the lengths
* of stdTrans and savSize is intended to be the size well enough
* to accommodate the max number of transitions in current tzdb data
* (203 for Asia/Tehran).
*
* @param in the input stream, not null
* @return the created object, not null
@ -438,6 +441,9 @@ public final class ZoneRules implements Serializable {
*/
static ZoneRules readExternal(DataInput in) throws IOException, ClassNotFoundException {
int stdSize = in.readInt();
if (stdSize > 1024) {
throw new InvalidObjectException("Too many transitions");
}
long[] stdTrans = (stdSize == 0) ? EMPTY_LONG_ARRAY
: new long[stdSize];
for (int i = 0; i < stdSize; i++) {
@ -448,6 +454,9 @@ public final class ZoneRules implements Serializable {
stdOffsets[i] = Ser.readOffset(in);
}
int savSize = in.readInt();
if (savSize > 1024) {
throw new InvalidObjectException("Too many saving offsets");
}
long[] savTrans = (savSize == 0) ? EMPTY_LONG_ARRAY
: new long[savSize];
for (int i = 0; i < savSize; i++) {
@ -458,6 +467,9 @@ public final class ZoneRules implements Serializable {
savOffsets[i] = Ser.readOffset(in);
}
int ruleSize = in.readByte();
if (ruleSize > 16) {
throw new InvalidObjectException("Too many transition rules");
}
ZoneOffsetTransitionRule[] rules = (ruleSize == 0) ?
EMPTY_LASTRULES : new ZoneOffsetTransitionRule[ruleSize];
for (int i = 0; i < ruleSize; i++) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@ -419,7 +419,13 @@ public class JarFile extends ZipFile {
if (verify) {
byte[] b = getBytes(manEntry);
if (!jvInitialized) {
jv = new JarVerifier(b);
if (JUZFA.getManifestNum(this) == 1) {
jv = new JarVerifier(manEntry.getName(), b);
} else {
if (JarVerifier.debug != null) {
JarVerifier.debug.println("Multiple MANIFEST.MF found. Treat JAR file as unsigned");
}
}
}
man = new Manifest(jv, new ByteArrayInputStream(b), getName());
} else {
@ -745,7 +751,7 @@ public class JarFile extends ZipFile {
mev = new ManifestEntryVerifier
(getManifestFromReference());
}
if (name.equals(MANIFEST_NAME)) {
if (name.equalsIgnoreCase(MANIFEST_NAME)) {
b = jv.manifestRawBytes;
} else {
b = getBytes(e);

View file

@ -94,7 +94,7 @@ public class JarInputStream extends ZipInputStream {
man.read(new ByteArrayInputStream(bytes));
closeEntry();
if (doVerify) {
jv = new JarVerifier(bytes);
jv = new JarVerifier(e.getName(), bytes);
mev = new ManifestEntryVerifier(man);
}
return (JarEntry)super.getNextEntry();

View file

@ -84,6 +84,9 @@ class JarVerifier {
/** the bytes for the manDig object */
byte manifestRawBytes[] = null;
/** the manifest name this JarVerifier is created upon */
final String manifestName;
/** controls eager signature validation */
boolean eagerValidation;
@ -93,7 +96,8 @@ class JarVerifier {
/** collect -DIGEST-MANIFEST values for deny list */
private List<Object> manifestDigests;
public JarVerifier(byte rawBytes[]) {
public JarVerifier(String name, byte rawBytes[]) {
manifestName = name;
manifestRawBytes = rawBytes;
sigFileSigners = new Hashtable<>();
verifiedSigners = new Hashtable<>();
@ -180,7 +184,7 @@ class JarVerifier {
// only set the jev object for entries that have a signature
// (either verified or not)
if (!name.equals(JarFile.MANIFEST_NAME)) {
if (!name.equalsIgnoreCase(JarFile.MANIFEST_NAME)) {
if (sigFileSigners.get(name) != null ||
verifiedSigners.get(name) != null) {
mev.setEntry(name, je);
@ -270,7 +274,8 @@ class JarVerifier {
}
sfv.setSignatureFile(bytes);
sfv.process(sigFileSigners, manifestDigests);
sfv.process(sigFileSigners, manifestDigests,
manifestName);
}
}
return;
@ -313,7 +318,7 @@ class JarVerifier {
sfv.setSignatureFile(bytes);
}
}
sfv.process(sigFileSigners, manifestDigests);
sfv.process(sigFileSigners, manifestDigests, manifestName);
} catch (IOException | CertificateException |
NoSuchAlgorithmException | SignatureException e) {
@ -419,9 +424,9 @@ class JarVerifier {
manDig = null;
// MANIFEST.MF is always treated as signed and verified,
// move its signers from sigFileSigners to verifiedSigners.
if (sigFileSigners.containsKey(JarFile.MANIFEST_NAME)) {
CodeSigner[] codeSigners = sigFileSigners.remove(JarFile.MANIFEST_NAME);
verifiedSigners.put(JarFile.MANIFEST_NAME, codeSigners);
if (sigFileSigners.containsKey(manifestName)) {
CodeSigner[] codeSigners = sigFileSigners.remove(manifestName);
verifiedSigners.put(manifestName, codeSigners);
}
}
@ -873,7 +878,7 @@ class JarVerifier {
*/
boolean isTrustedManifestEntry(String name) {
// How many signers? MANIFEST.MF is always verified
CodeSigner[] forMan = verifiedSigners.get(JarFile.MANIFEST_NAME);
CodeSigner[] forMan = verifiedSigners.get(manifestName);
if (forMan == null) {
return true;
}

View file

@ -226,6 +226,7 @@ public class ZipFile implements ZipConstants, Closeable {
Integer.toHexString(mode));
}
String name = file.getPath();
file = new File(name);
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
@ -1032,6 +1033,18 @@ public class ZipFile implements ZipConstants, Closeable {
}
}
/**
* Returns the number of the META-INF/MANIFEST.MF entries, case insensitive.
* When this number is greater than 1, JarVerifier will treat a file as
* unsigned.
*/
private int getManifestNum() {
synchronized (this) {
ensureOpen();
return res.zsrc.manifestNum;
}
}
/**
* Returns the name of the META-INF/MANIFEST.MF entry, ignoring
* case. If {@code onlyIfSignatureRelatedFiles} is true, we only return the
@ -1079,6 +1092,10 @@ public class ZipFile implements ZipConstants, Closeable {
return ((ZipFile)jar).getManifestAndSignatureRelatedFiles();
}
@Override
public int getManifestNum(JarFile jar) {
return ((ZipFile)jar).getManifestNum();
}
@Override
public String getManifestName(JarFile jar, boolean onlyIfHasSignatureRelatedFiles) {
return ((ZipFile)jar).getManifestName(onlyIfHasSignatureRelatedFiles);
}
@ -1131,6 +1148,7 @@ public class ZipFile implements ZipConstants, Closeable {
private byte[] comment; // zip file comment
// list of meta entries in META-INF dir
private int manifestPos = -1; // position of the META-INF/MANIFEST.MF, if exists
private int manifestNum = 0; // number of META-INF/MANIFEST.MF, case insensitive
private int[] signatureMetaNames; // positions of signature related entries, if such exist
private int[] metaVersions; // list of unique versions found in META-INF/versions/
private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
@ -1313,6 +1331,7 @@ public class ZipFile implements ZipConstants, Closeable {
entries = null;
table = null;
manifestPos = -1;
manifestNum = 0;
signatureMetaNames = null;
metaVersions = EMPTY_META_VERSIONS;
}
@ -1504,6 +1523,7 @@ public class ZipFile implements ZipConstants, Closeable {
int pos = 0;
int entryPos = CENHDR;
int limit = cen.length - ENDHDR;
manifestNum = 0;
while (entryPos <= limit) {
if (idx >= entriesLength) {
// This will only happen if the zip file has an incorrect
@ -1522,6 +1542,7 @@ public class ZipFile implements ZipConstants, Closeable {
// nlen is at least META_INF_LENGTH
if (isManifestName(entryPos + META_INF_LEN, nlen - META_INF_LEN)) {
manifestPos = pos;
manifestNum++;
} else {
if (isSignatureRelated(entryPos, nlen)) {
if (signatureNames == null)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2021, 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
@ -37,6 +37,7 @@ public interface JavaUtilZipFileAccess {
public boolean startsWithLocHeader(ZipFile zip);
public List<String> getManifestAndSignatureRelatedFiles(JarFile zip);
public String getManifestName(JarFile zip, boolean onlyIfSignatureRelatedFiles);
public int getManifestNum(JarFile zip);
public int[] getMetaInfVersions(JarFile zip);
public Enumeration<JarEntry> entries(ZipFile zip);
public Stream<JarEntry> stream(ZipFile zip);

View file

@ -538,6 +538,9 @@ public class ClassReader {
} else if (Constants.SYNTHETIC.equals(attributeName)) {
accessFlags |= Opcodes.ACC_SYNTHETIC;
} else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) {
if (attributeLength > classFileBuffer.length - currentAttributeOffset) {
throw new IllegalArgumentException();
}
sourceDebugExtension =
readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]);
} else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
@ -1548,6 +1551,9 @@ public class ClassReader {
final int maxLocals = readUnsignedShort(currentOffset + 2);
final int codeLength = readInt(currentOffset + 4);
currentOffset += 8;
if (codeLength > classFileBuffer.length - currentOffset) {
throw new IllegalArgumentException();
}
// Read the bytecode 'code' array to create a label for each referenced instruction.
final int bytecodeStartOffset = currentOffset;

View file

@ -24,16 +24,36 @@
*/
package sun.net.ftp.impl;
import java.net.*;
import java.io.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.text.DateFormat;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
@ -44,7 +64,11 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import sun.net.ftp.*;
import sun.net.ftp.FtpDirEntry;
import sun.net.ftp.FtpDirParser;
import sun.net.ftp.FtpProtocolException;
import sun.net.ftp.FtpReplyCode;
import sun.net.util.IPAddressUtil;
import sun.util.logging.PlatformLogger;
@ -107,13 +131,15 @@ public class FtpClient extends sun.net.ftp.FtpClient {
private static Pattern[] patterns;
private static Pattern linkp = Pattern.compile("(\\p{Print}+) \\-\\> (\\p{Print}+)$");
private DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, java.util.Locale.US);
private static final boolean acceptPasvAddressVal;
static {
final int vals[] = {0, 0};
final String acceptPasvAddress[] = {null};
@SuppressWarnings("removal")
final String enc = AccessController.doPrivileged(
new PrivilegedAction<String>() {
public String run() {
acceptPasvAddress[0] = System.getProperty("jdk.net.ftp.trustPasvAddress", "false");
vals[0] = Integer.getInteger("sun.net.client.defaultReadTimeout", 300_000).intValue();
vals[1] = Integer.getInteger("sun.net.client.defaultConnectTimeout", 300_000).intValue();
return System.getProperty("file.encoding", "ISO8859_1");
@ -144,6 +170,8 @@ public class FtpClient extends sun.net.ftp.FtpClient {
for (int i = 0; i < patStrings.length; i++) {
patterns[i] = Pattern.compile(patStrings[i]);
}
acceptPasvAddressVal = Boolean.parseBoolean(acceptPasvAddress[0]);
}
/**
@ -610,7 +638,6 @@ public class FtpClient extends sun.net.ftp.FtpClient {
//
// The regular expression is a bit more complex this time, because
// the parenthesis are optionals and we have to use 3 groups.
if (pasvPat == null) {
pasvPat = Pattern.compile("227 .* \\(?(\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}),(\\d{1,3}),(\\d{1,3})\\)?");
}
@ -622,8 +649,15 @@ public class FtpClient extends sun.net.ftp.FtpClient {
port = Integer.parseInt(m.group(3)) + (Integer.parseInt(m.group(2)) << 8);
// IP address is simple
String s = m.group(1).replace(',', '.');
if (!IPAddressUtil.isIPv4LiteralAddress(s))
throw new FtpProtocolException("PASV failed : " + serverAnswer);
if (acceptPasvAddressVal) {
dest = new InetSocketAddress(s, port);
} else {
dest = validatePasvAddress(port, s, server.getInetAddress());
}
}
// Got everything, let's open the socket!
Socket s;
if (proxy != null) {
@ -678,6 +712,80 @@ public class FtpClient extends sun.net.ftp.FtpClient {
return s;
}
static final String ERROR_MSG = "Address should be the same as originating server";
/**
* Returns an InetSocketAddress, based on value of acceptPasvAddressVal
* and other conditions such as the server address returned by pasv
* is not a hostname, is a socks proxy, or the loopback. An exception
* is thrown if none of the valid conditions are met.
*/
private InetSocketAddress validatePasvAddress(int port, String s, InetAddress address)
throws FtpProtocolException
{
if (address == null) {
return InetSocketAddress.createUnresolved(serverAddr.getHostName(), port);
}
String serverAddress = address.getHostAddress();
if (serverAddress.equals(s)) {
return new InetSocketAddress(s, port);
} else if (address.isLoopbackAddress() && s.startsWith("127.")) { // can be 127.0
return new InetSocketAddress(s, port);
} else if (address.isLoopbackAddress()) {
if (privilegedLocalHost().getHostAddress().equals(s)) {
return new InetSocketAddress(s, port);
} else {
throw new FtpProtocolException(ERROR_MSG);
}
} else if (s.startsWith("127.")) {
if (privilegedLocalHost().equals(address)) {
return new InetSocketAddress(s, port);
} else {
throw new FtpProtocolException(ERROR_MSG);
}
}
String hostName = address.getHostName();
if (!(IPAddressUtil.isIPv4LiteralAddress(hostName) || IPAddressUtil.isIPv6LiteralAddress(hostName))) {
InetAddress[] names = privilegedGetAllByName(hostName);
String resAddress = Arrays
.stream(names)
.map(InetAddress::getHostAddress)
.filter(s::equalsIgnoreCase)
.findFirst()
.orElse(null);
if (resAddress != null) {
return new InetSocketAddress(s, port);
}
}
throw new FtpProtocolException(ERROR_MSG);
}
private static InetAddress privilegedLocalHost() throws FtpProtocolException {
PrivilegedExceptionAction<InetAddress> action = InetAddress::getLocalHost;
try {
@SuppressWarnings("removal")
var tmp = AccessController.doPrivileged(action);
return tmp;
} catch (Exception e) {
var ftpEx = new FtpProtocolException(ERROR_MSG);
ftpEx.initCause(e);
throw ftpEx;
}
}
private static InetAddress[] privilegedGetAllByName(String hostName) throws FtpProtocolException {
PrivilegedExceptionAction<InetAddress[]> pAction = () -> InetAddress.getAllByName(hostName);
try {
@SuppressWarnings("removal")
var tmp =AccessController.doPrivileged(pAction);
return tmp;
} catch (Exception e) {
var ftpEx = new FtpProtocolException(ERROR_MSG);
ftpEx.initCause(e);
throw ftpEx;
}
}
/**
* Opens a data connection with the server according to the set mode
* (ACTIVE or PASSIVE) then send the command passed as an argument.
@ -688,7 +796,6 @@ public class FtpClient extends sun.net.ftp.FtpClient {
*/
private Socket openDataConnection(String cmd) throws sun.net.ftp.FtpProtocolException, IOException {
Socket clientSocket;
if (passiveMode) {
try {
return openPassiveDataConnection(cmd);

View file

@ -331,7 +331,18 @@ public class SignerInfo implements DerEncoder {
throws NoSuchAlgorithmException, SignatureException {
try {
Timestamp timestamp = getTimestamp();
Timestamp timestamp = null;
try {
timestamp = getTimestamp();
} catch (Exception e) {
// Log exception and continue. This allows for the case
// where, if there are no other errors, the code is
// signed but w/o a timestamp.
if (debug != null) {
debug.println("Unexpected exception while getting" +
" timestamp: " + e);
}
}
ContentInfo content = block.getContentInfo();
if (data == null) {
@ -471,7 +482,7 @@ public class SignerInfo implements DerEncoder {
if (sig.verify(encryptedDigest)) {
return this;
}
} catch (IOException | CertificateException e) {
} catch (IOException e) {
throw new SignatureException("Error verifying signature", e);
}
return null;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@ -270,7 +270,7 @@ public class SignatureFileVerifier {
*
*/
public void process(Hashtable<String, CodeSigner[]> signers,
List<Object> manifestDigests)
List<Object> manifestDigests, String manifestName)
throws IOException, SignatureException, NoSuchAlgorithmException,
JarException, CertificateException
{
@ -279,7 +279,7 @@ public class SignatureFileVerifier {
Object obj = null;
try {
obj = Providers.startJarVerification();
processImpl(signers, manifestDigests);
processImpl(signers, manifestDigests, manifestName);
} finally {
Providers.stopJarVerification(obj);
}
@ -287,7 +287,7 @@ public class SignatureFileVerifier {
}
private void processImpl(Hashtable<String, CodeSigner[]> signers,
List<Object> manifestDigests)
List<Object> manifestDigests, String manifestName)
throws IOException, SignatureException, NoSuchAlgorithmException,
JarException, CertificateException
{
@ -368,7 +368,7 @@ public class SignatureFileVerifier {
}
// MANIFEST.MF is always regarded as signed
updateSigners(newSigners, signers, JarFile.MANIFEST_NAME);
updateSigners(newSigners, signers, manifestName);
}
/**

View file

@ -25,6 +25,7 @@
package java.awt.datatransfer;
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
@ -321,9 +322,12 @@ MimeTypeParameterList(rawdata.substring(semIndex));
ClassNotFoundException {
String s = in.readUTF();
if (s == null || s.length() == 0) { // long mime type
byte[] ba = new byte[in.readInt()];
in.readFully(ba);
s = new String(ba);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len = in.readInt();
while (len-- > 0) {
baos.write(in.readByte());
}
s = baos.toString();
}
try {
parse(s);

View file

@ -426,7 +426,6 @@ abstract class CMap {
try {
this.uvs = new UVS(buffer, offset);
} catch (Throwable t) {
t.printStackTrace();
}
}
return;

View file

@ -518,6 +518,10 @@ public class TrueTypeFont extends FileFont {
&& getDirectoryEntry(hheaTag) == null) {
throw new FontFormatException("missing hhea table");
}
ByteBuffer maxpTable = getTableBuffer(maxpTag);
if (maxpTable.getChar(4) == 0) {
throw new FontFormatException("zero glyphs");
}
initNames();
} catch (Exception e) {
if (FontUtilities.isLogging()) {
@ -981,24 +985,36 @@ public class TrueTypeFont extends FileFont {
private void setStrikethroughMetrics(ByteBuffer os_2Table, int upem) {
if (os_2Table == null || os_2Table.capacity() < 30 || upem < 0) {
stSize = .05f;
stPos = -.4f;
stSize = 0.05f;
stPos = -0.4f;
return;
}
ShortBuffer sb = os_2Table.asShortBuffer();
stSize = sb.get(13) / (float)upem;
stPos = -sb.get(14) / (float)upem;
if (stSize < 0f) {
stSize = 0.05f;
}
if (Math.abs(stPos) > 2.0f) {
stPos = -0.4f;
}
}
private void setUnderlineMetrics(ByteBuffer postTable, int upem) {
if (postTable == null || postTable.capacity() < 12 || upem < 0) {
ulSize = .05f;
ulPos = .1f;
ulSize = 0.05f;
ulPos = 0.1f;
return;
}
ShortBuffer sb = postTable.asShortBuffer();
ulSize = sb.get(5) / (float)upem;
ulPos = -sb.get(4) / (float)upem;
if (ulSize < 0f) {
ulSize = 0.05f;
}
if (Math.abs(ulPos) > 2.0f) {
ulPos = 0.1f;
}
}
@Override

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
*/
/*
@ -39,6 +39,8 @@ import java.io.IOException;
*
* @author Michael Glavassevich, IBM
* @author Neil Graham, IBM
*
* @LastModified: Apr 2021
*/
public class XML11EntityScanner
@ -696,7 +698,7 @@ public class XML11EntityScanner
sawIncompleteSurrogatePair)){
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"IllegalQName",
null,
new Object[]{rawname},
XMLErrorReporter.SEVERITY_FATAL_ERROR);
}
//check the result: localpart

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
*/
/*
@ -55,6 +55,7 @@ import java.util.Locale;
* @author Arnaud Le Hors, IBM
* @author K.Venugopal Sun Microsystems
*
* @LastModified: Apr 2021
*/
public class XMLEntityScanner implements XMLLocator {
@ -860,6 +861,14 @@ public class XMLEntityScanner implements XMLLocator {
prefix = fSymbolTable.addSymbol(fCurrentEntity.ch,
offset, prefixLength);
int len = length - prefixLength - 1;
int startLocal = index +1;
if (!XMLChar.isNCNameStart(fCurrentEntity.ch[startLocal])){
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"IllegalQName",
new Object[]{rawname},
XMLErrorReporter.SEVERITY_FATAL_ERROR);
}
//check the result: localpart
checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, index + 1, len);
localpart = fSymbolTable.addSymbol(fCurrentEntity.ch,

View file

@ -278,7 +278,7 @@
# Namespaces support
# 4. Using Qualified Names
IllegalQName = Element or attribute do not match QName production: QName::=(NCName':')?NCName.
IllegalQName = Element or attribute \"{0}\" do not match QName production: QName::=(NCName':')?NCName.
ElementXMLNSPrefix = Element \"{0}\" cannot have \"xmlns\" as its prefix.
ElementPrefixUnbound = The prefix \"{0}\" for element \"{1}\" is not bound.
AttributePrefixUnbound = The prefix \"{2}\" for attribute \"{1}\" associated with an element type \"{0}\" is not bound.

View file

@ -43,6 +43,7 @@ import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.JdkXmlUtils;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
@ -1978,21 +1979,21 @@ abstract public class ToStream extends SerializerBase {
String doctypeSystem = getDoctypeSystem();
if (null != doctypeSystem)
{
if (null == doctypePublic)
writer.write(" SYSTEM \"");
else
writer.write(" \"");
char quote = JdkXmlUtils.getQuoteChar(doctypeSystem);
if (null == doctypePublic) {
writer.write(" SYSTEM");
}
writer.write(" ");
writer.write(quote);
writer.write(doctypeSystem);
writer.write(quote);
if (closeDecl)
{
writer.write("\">");
writer.write(">");
writer.write(m_lineSep, 0, m_lineSepLen);
closeDecl = false; // done closing
}
else
writer.write('\"');
}
boolean dothis = false;
if (dothis)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -33,6 +33,7 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import jdk.xml.internal.JdkXmlUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
@ -62,7 +63,7 @@ import org.xml.sax.helpers.LocatorImpl;
* parameters and filters if any during serialization.
*
* @xsl.usage internal
* @LastModified: Oct 2017
* @LastModified: Apr 2021
*/
final class DOM3TreeWalker {
@ -501,7 +502,7 @@ final class DOM3TreeWalker {
// DOCTYPE internal subset via an event call, so we write it
// out here.
Writer writer = fSerializer.getWriter();
StringBuffer dtd = new StringBuffer();
StringBuilder dtd = new StringBuilder();
dtd.append("<!DOCTYPE ");
dtd.append(docTypeName);
@ -512,13 +513,14 @@ final class DOM3TreeWalker {
}
if (null != systemId) {
char quote = JdkXmlUtils.getQuoteChar(systemId);
if (null == publicId) {
dtd.append(" SYSTEM \"");
dtd.append(" SYSTEM ").append(quote);
} else {
dtd.append(" \"");
dtd.append(" ").append(quote);
}
dtd.append(systemId);
dtd.append('\"');
dtd.append(quote);
}
dtd.append(" [ ");

View file

@ -366,6 +366,22 @@ public class JdkXmlUtils {
return tf;
}
/**
* Returns the character to be used to quote the input content. Between
* single and double quotes, this method returns the one that is not found
* in the input. Returns double quote by default.
*
* @param s the input string
* @return returns the quote not found in the input
*/
public static char getQuoteChar(String s) {
if (s != null && s.indexOf('"') > -1) {
return '\'';
} else {
return '"';
}
}
private static XMLReader getXMLReaderWSAXFactory(boolean overrideDefaultParser) {
SAXParserFactory saxFactory = getSAXFactory(overrideDefaultParser);
try {

View file

@ -582,14 +582,39 @@ class ServerImpl implements TimeSource {
start = space+1;
String version = requestLine.substring (start);
Headers headers = req.headers();
String s = headers.getFirst ("Transfer-encoding");
/* check key for illegal characters */
for (var k : headers.keySet()) {
if (!isValidHeaderKey(k)) {
reject(Code.HTTP_BAD_REQUEST, requestLine,
"Header key contains illegal characters");
return;
}
}
/* checks for unsupported combinations of lengths and encodings */
if (headers.containsKey("Content-Length") &&
(headers.containsKey("Transfer-encoding") || headers.get("Content-Length").size() > 1)) {
reject(Code.HTTP_BAD_REQUEST, requestLine,
"Conflicting or malformed headers detected");
return;
}
long clen = 0L;
if (s !=null && s.equalsIgnoreCase ("chunked")) {
String headerValue = null;
List<String> teValueList = headers.get("Transfer-encoding");
if (teValueList != null && !teValueList.isEmpty()) {
headerValue = teValueList.get(0);
}
if (headerValue != null) {
if (headerValue.equalsIgnoreCase("chunked") && teValueList.size() == 1) {
clen = -1L;
} else {
s = headers.getFirst ("Content-Length");
if (s != null) {
clen = Long.parseLong(s);
reject(Code.HTTP_NOT_IMPLEMENTED,
requestLine, "Unsupported Transfer-Encoding value");
return;
}
} else {
headerValue = headers.getFirst("Content-Length");
if (headerValue != null) {
clen = Long.parseLong(headerValue);
}
if (clen == 0) {
requestCompleted(connection);
@ -907,4 +932,24 @@ class ServerImpl implements TimeSource {
return secs * 1000;
}
}
/*
* Validates a RFC 7230 header-key.
*/
static boolean isValidHeaderKey(String token) {
if (token == null) return false;
boolean isValidChar;
char[] chars = token.toCharArray();
String validSpecialChars = "!#$%&'*+-.^_`|~";
for (char c : chars) {
isValidChar = ((c >= 'a') && (c <= 'z')) ||
((c >= 'A') && (c <= 'Z')) ||
((c >= '0') && (c <= '9'));
if (!isValidChar && validSpecialChars.indexOf(c) == -1) {
return false;
}
}
return !token.isEmpty();
}
}

View file

@ -795,8 +795,12 @@ public class Main {
CodeSigner[] signers = je.getCodeSigners();
boolean isSigned = (signers != null);
anySigned |= isSigned;
hasUnsignedEntry |= !je.isDirectory() && !isSigned
&& !signatureRelated(name);
boolean unsignedEntry = !isSigned
&& ((!je.isDirectory() && !signatureRelated(name))
// a directory entry but with a suspicious size
|| (je.isDirectory() && je.getSize() > 0));
hasUnsignedEntry |= unsignedEntry;
int inStoreWithAlias = inKeyStore(signers);
@ -818,7 +822,9 @@ public class Main {
sb.append(isSigned ? rb.getString("s") : rb.getString("SPACE"))
.append(inManifest ? rb.getString("m") : rb.getString("SPACE"))
.append(inStore ? rb.getString("k") : rb.getString("SPACE"))
.append((inStoreWithAlias & NOT_ALIAS) != 0 ? 'X' : ' ')
.append((inStoreWithAlias & NOT_ALIAS) != 0 ?
rb.getString("X") : rb.getString("SPACE"))
.append(unsignedEntry ? rb.getString("q") : rb.getString("SPACE"))
.append(rb.getString("SPACE"));
sb.append('|');
}
@ -846,10 +852,14 @@ public class Main {
.append(rb
.getString(".Signature.related.entries."))
.append("\n\n");
} else {
} else if (unsignedEntry) {
sb.append('\n').append(tab)
.append(rb.getString(".Unsigned.entries."))
.append("\n\n");
} else {
sb.append('\n').append(tab)
.append(rb.getString(".Directory.entries."))
.append("\n\n");
}
}
@ -924,6 +934,11 @@ public class Main {
System.out.println(rb.getString(
".X.not.signed.by.specified.alias.es."));
}
if (hasUnsignedEntry) {
System.out.println(rb.getString(
".q.unsigned.entry"));
}
}
if (man == null) {
System.out.println();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2021, 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
@ -133,6 +133,8 @@ public class Resources extends java.util.ListResourceBundle {
{"s", "s"},
{"m", "m"},
{"k", "k"},
{"X", "X"},
{"q", "?"},
{".and.d.more.", "(and %d more)"},
{".s.signature.was.verified.",
" s = signature was verified "},
@ -142,9 +144,12 @@ public class Resources extends java.util.ListResourceBundle {
" k = at least one certificate was found in keystore"},
{".X.not.signed.by.specified.alias.es.",
" X = not signed by specified alias(es)"},
{".q.unsigned.entry",
" ? = unsigned entry"},
{"no.manifest.", "no manifest."},
{".Signature.related.entries.","(Signature related entries)"},
{".Unsigned.entries.", "(Unsigned entries)"},
{".Directory.entries.", "(Directory entries)"},
{"jar.is.unsigned",
"jar is unsigned."},
{"jar.treated.unsigned",

View file

@ -329,6 +329,7 @@ public class TestLargePagesFlags {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args);
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
return output;
}

View file

@ -62,6 +62,7 @@ public class ReadFromNoaccessArea {
if (output.getStdout() != null && output.getStdout().contains("WB_ReadFromNoaccessArea method is useless")) {
throw new SkippedException("There is no protected page in ReservedHeapSpace in these circumstance");
}
output.shouldNotHaveExitValue(0);
if (Platform.isWindows()) {
output.shouldContain("EXCEPTION_ACCESS_VIOLATION");
} else if (Platform.isOSX()) {
@ -76,7 +77,6 @@ public class ReadFromNoaccessArea {
// This method calls whitebox method reading from noaccess area
public static void main(String args[]) throws Exception {
WhiteBox.getWhiteBox().readFromNoaccessArea();
throw new Exception("Call of readFromNoaccessArea succeeded! This is wrong. Crash expected. Test failed.");
}
}

View file

@ -44,11 +44,9 @@ import sun.hotspot.WhiteBox;
public class ReserveMemory {
public static void main(String args[]) throws Exception {
if (args.length > 0) {
// expected to crash
WhiteBox.getWhiteBox().readReservedMemory();
throw new Exception("Read of reserved/uncommitted memory unexpectedly succeeded, expected crash!");
}
} else {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-Xbootclasspath/a:.",
"-XX:+UnlockDiagnosticVMOptions",
@ -59,6 +57,7 @@ public class ReserveMemory {
"test");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldNotHaveExitValue(0);
if (Platform.isWindows()) {
output.shouldContain("EXCEPTION_ACCESS_VIOLATION");
} else if (Platform.isOSX()) {
@ -68,3 +67,4 @@ public class ReserveMemory {
}
}
}
}

View file

@ -226,7 +226,6 @@ java/awt/TrayIcon/PopupMenuLeakTest/PopupMenuLeakTest.java 8196440 linux-all
java/awt/Window/ShapedAndTranslucentWindows/SetShapeAndClick.java 8197936 macosx-all
java/awt/Window/ShapedAndTranslucentWindows/SetShapeDynamicallyAndClick.java 8013450 macosx-all
java/awt/Window/ShapedAndTranslucentWindows/ShapedTranslucentWindowClick.java 8013450 macosx-all
java/awt/Window/MultiWindowApp/MultiWindowAppTest.java 8159904 linux-all
java/awt/Window/MultiWindowApp/ChildAlwaysOnTopTest.java 8222323 windows-all
java/awt/Window/ShapedAndTranslucentWindows/FocusAWTTest.java 8222328 windows-all,linux-all,macosx-all
java/awt/Window/ShapedAndTranslucentWindows/Shaped.java 8222328 windows-all,linux-all,macosx-all
@ -243,7 +242,7 @@ java/awt/FontMetrics/FontCrash.java 8198336 windows-all
java/awt/image/BufferedImage/ICMColorDataTest/ICMColorDataTest.java 8233028 generic-all
java/awt/image/DrawImage/IncorrectAlphaSurface2SW.java 8056077 linux-all
java/awt/image/DrawImage/BlitRotateClippedArea.java 8255724 linux-all
java/awt/image/multiresolution/MultiresolutionIconTest.java 8169187 macosx-all,windows-all
java/awt/image/multiresolution/MultiresolutionIconTest.java 8169187,8252812 macosx-all,windows-all,linux-x64
java/awt/print/Headless/HeadlessPrinterJob.java 8196088 windows-all
sun/awt/datatransfer/SuplementaryCharactersTransferTest.java 8011371 generic-all
sun/awt/shell/ShellFolderMemoryLeak.java 8197794 windows-all
@ -529,6 +528,8 @@ java/awt/MenuBar/TestNoScreenMenuBar.java 8265987 macosx-all
java/awt/Graphics2D/DrawString/DrawRotatedStringUsingRotatedFont.java 8266283 generic-all
java/awt/KeyboardFocusmanager/TypeAhead/ButtonActionKeyTest/ButtonActionKeyTest.java 8257529 windows-x64
java/awt/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64
############################################################################
# jdk_beans
@ -746,6 +747,8 @@ javax/swing/JEditorPane/6917744/bug6917744.java 8213124 macosx-all
javax/swing/JRootPane/4670486/bug4670486.java 8042381 macosx-all
javax/swing/JPopupMenu/4634626/bug4634626.java 8017175 macosx-all
javax/swing/plaf/basic/BasicHTML/4251579/bug4251579.java 8137101 linux-x64
sanity/client/SwingSet/src/ToolTipDemoTest.java 8225012 windows-all,macosx-all
sanity/client/SwingSet/src/ScrollPaneDemoTest.java 8225013 linux-all
sanity/client/SwingSet/src/ButtonDemoScreenshotTest.java 8265770 macosx-all

View file

@ -21,7 +21,7 @@
* questions.
*/
/**
/*
* @test
* @summary After calling frame.toBack() dialog goes to the back on Ubuntu 12.04
* @key headful
@ -38,22 +38,24 @@ public class MultiWindowAppTest {
Window win1 = new Frame();
Window win2 = new Dialog((Frame) null);
int delay = 300;
win1.setBounds(100, 100, 200, 200);
win1.setBackground(Color.RED);
win1.setVisible(true);
Robot robot = new Robot();
robot.delay(200);
robot.delay(delay);
robot.waitForIdle();
win2.setBounds(win1.getBounds());
win2.setVisible(true);
robot.delay(200);
robot.delay(delay);
robot.waitForIdle();
win1.toFront();
robot.delay(200);
robot.delay(delay);
robot.waitForIdle();
Point point = win1.getLocationOnScreen();
@ -66,7 +68,7 @@ public class MultiWindowAppTest {
}
win1.toBack();
robot.delay(200);
robot.delay(delay);
robot.waitForIdle();
color = robot.getPixelColor(point.x + 100, point.y + 100);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2021, 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,7 +23,7 @@
/*
* @test
* @bug 6802846 8172529 8227758
* @bug 6802846 8172529 8227758 8260960
* @summary jarsigner needs enhanced cert validation(options)
* @library /test/lib
* @run main/timeout=240 ConciseJarsigner
@ -112,23 +112,26 @@ public class ConciseJarsigner {
.filter(s -> s.contains(year))
.count() == 12);
// 4 groups: MANIFST, unrelated, signed, unsigned
// 5 groups: MANIFEST, signature related entries, directory entries,
// signed entries, and unsigned entries.
Asserts.assertTrue(js("-verify a.jar -verbose:summary")
.asLines().stream()
.filter(s -> s.contains(year))
.count() == 4);
.count() == 5);
// still 4 groups, but MANIFEST group has no other file
// still 5 groups, but MANIFEST group and directiry entry group
// have no other file
Asserts.assertTrue(js("-verify a.jar -verbose:summary")
.asLines().stream()
.filter(s -> s.contains("more)"))
.count() == 3);
// 5 groups: MANIFEST, unrelated, signed by a1/a2, signed by a2, unsigned
// 6 groups: MANIFEST, signature related entries, directory entries,
// signed entries by a1/a2, signed entries by a2, and unsigned entries.
Asserts.assertTrue(js("-verify a.jar -verbose:summary -certs")
.asLines().stream()
.filter(s -> s.contains(year))
.count() == 5);
.count() == 6);
// 2 for MANIFEST, 2*2 for A1/A2, 2 for A3/A4
Asserts.assertTrue(js("-verify a.jar -verbose -certs")
@ -148,7 +151,8 @@ public class ConciseJarsigner {
.filter(s -> s.contains("[certificate"))
.count() == 5);
// still 5 groups, but MANIFEST group has no other file
// still 6 groups, but MANIFEST group and directory entry group
// have no other file
Asserts.assertTrue(js("-verify a.jar -verbose:summary -certs")
.asLines().stream()
.filter(s -> s.contains("more)"))