Merge
This commit is contained in:
commit
9ebbeec405
@ -46,6 +46,8 @@ char *getPosixLocale(int cat) {
|
||||
|
||||
#define LOCALEIDLENGTH 128
|
||||
char *getMacOSXLocale(int cat) {
|
||||
const char* retVal = NULL;
|
||||
|
||||
switch (cat) {
|
||||
case LC_MESSAGES:
|
||||
{
|
||||
@ -72,41 +74,7 @@ char *getMacOSXLocale(int cat) {
|
||||
}
|
||||
CFRelease(languages);
|
||||
|
||||
// Language IDs use the language designators and (optional) region
|
||||
// and script designators of BCP 47. So possible formats are:
|
||||
//
|
||||
// "en" (language designator only)
|
||||
// "haw" (3-letter lanuage designator)
|
||||
// "en-GB" (language with alpha-2 region designator)
|
||||
// "es-419" (language with 3-digit UN M.49 area code)
|
||||
// "zh-Hans" (language with ISO 15924 script designator)
|
||||
// "zh-Hans-US" (language with ISO 15924 script designator and region)
|
||||
// "zh-Hans-419" (language with ISO 15924 script designator and UN M.49)
|
||||
//
|
||||
// In the case of region designators (alpha-2 and/or UN M.49), we convert
|
||||
// to our locale string format by changing '-' to '_'. That is, if
|
||||
// the '-' is followed by fewer than 4 chars.
|
||||
char* scriptOrRegion = strchr(languageString, '-');
|
||||
if (scriptOrRegion != NULL) {
|
||||
int length = strlen(scriptOrRegion);
|
||||
if (length > 5) {
|
||||
// Region and script both exist. Honor the script for now
|
||||
scriptOrRegion[5] = '\0';
|
||||
} else if (length < 5) {
|
||||
*scriptOrRegion = '_';
|
||||
|
||||
assert((length == 3 &&
|
||||
// '-' followed by a 2 character region designator
|
||||
isalpha(scriptOrRegion[1]) &&
|
||||
isalpha(scriptOrRegion[2])) ||
|
||||
(length == 4 &&
|
||||
// '-' followed by a 3-digit UN M.49 area code
|
||||
isdigit(scriptOrRegion[1]) &&
|
||||
isdigit(scriptOrRegion[2]) &&
|
||||
isdigit(scriptOrRegion[3])));
|
||||
}
|
||||
}
|
||||
const char* retVal = languageString;
|
||||
retVal = languageString;
|
||||
|
||||
// Special case for Portuguese in Brazil:
|
||||
// The language code needs the "_BR" region code (to distinguish it
|
||||
@ -120,20 +88,58 @@ char *getMacOSXLocale(int cat) {
|
||||
strcmp(localeString, "pt_BR") == 0) {
|
||||
retVal = localeString;
|
||||
}
|
||||
return strdup(retVal);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
char localeString[LOCALEIDLENGTH];
|
||||
if (CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()),
|
||||
localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding())) {
|
||||
return strdup(localeString);
|
||||
if (!CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()),
|
||||
localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding())) {
|
||||
return NULL;
|
||||
}
|
||||
retVal = localeString;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (retVal != NULL) {
|
||||
// Language IDs use the language designators and (optional) region
|
||||
// and script designators of BCP 47. So possible formats are:
|
||||
//
|
||||
// "en" (language designator only)
|
||||
// "haw" (3-letter lanuage designator)
|
||||
// "en-GB" (language with alpha-2 region designator)
|
||||
// "es-419" (language with 3-digit UN M.49 area code)
|
||||
// "zh-Hans" (language with ISO 15924 script designator)
|
||||
// "zh-Hans-US" (language with ISO 15924 script designator and region)
|
||||
// "zh-Hans-419" (language with ISO 15924 script designator and UN M.49)
|
||||
//
|
||||
// In the case of region designators (alpha-2 and/or UN M.49), we convert
|
||||
// to our locale string format by changing '-' to '_'. That is, if
|
||||
// the '-' is followed by fewer than 4 chars.
|
||||
char* scriptOrRegion = strchr(retVal, '-');
|
||||
if (scriptOrRegion != NULL) {
|
||||
int length = strlen(scriptOrRegion);
|
||||
if (length > 5) {
|
||||
// Region and script both exist. Honor the script for now
|
||||
scriptOrRegion[5] = '\0';
|
||||
} else if (length < 5) {
|
||||
*scriptOrRegion = '_';
|
||||
|
||||
assert((length == 3 &&
|
||||
// '-' followed by a 2 character region designator
|
||||
isalpha(scriptOrRegion[1]) &&
|
||||
isalpha(scriptOrRegion[2])) ||
|
||||
(length == 4 &&
|
||||
// '-' followed by a 3-digit UN M.49 area code
|
||||
isdigit(scriptOrRegion[1]) &&
|
||||
isdigit(scriptOrRegion[2]) &&
|
||||
isdigit(scriptOrRegion[3])));
|
||||
}
|
||||
}
|
||||
|
||||
return strdup(retVal);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -779,8 +779,7 @@ public final class SplittableRandom {
|
||||
* @return a stream of pseudorandom {@code double} values,
|
||||
* each with the given origin (inclusive) and bound (exclusive)
|
||||
* @throws IllegalArgumentException if {@code streamSize} is
|
||||
* less than zero
|
||||
* @throws IllegalArgumentException if {@code randomNumberOrigin}
|
||||
* less than zero, or {@code randomNumberOrigin}
|
||||
* is greater than or equal to {@code randomNumberBound}
|
||||
*/
|
||||
public DoubleStream doubles(long streamSize, double randomNumberOrigin,
|
||||
|
@ -1226,6 +1226,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
} else {
|
||||
nextIndex = NONE;
|
||||
nextItem = null;
|
||||
if (lastRet == REMOVED) detach();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
|
@ -699,8 +699,7 @@ public class ThreadLocalRandom extends Random {
|
||||
* @return a stream of pseudorandom {@code double} values,
|
||||
* each with the given origin (inclusive) and bound (exclusive)
|
||||
* @throws IllegalArgumentException if {@code streamSize} is
|
||||
* less than zero
|
||||
* @throws IllegalArgumentException if {@code randomNumberOrigin}
|
||||
* less than zero, or {@code randomNumberOrigin}
|
||||
* is greater than or equal to {@code randomNumberBound}
|
||||
* @since 1.8
|
||||
*/
|
||||
|
@ -53,16 +53,14 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
||||
*
|
||||
* <dl>
|
||||
* <dt><b><i>Non-fair mode (default)</i></b>
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* When constructed as non-fair (the default), the order of entry
|
||||
* <dd>When constructed as non-fair (the default), the order of entry
|
||||
* to the read and write lock is unspecified, subject to reentrancy
|
||||
* constraints. A nonfair lock that is continuously contended may
|
||||
* indefinitely postpone one or more reader or writer threads, but
|
||||
* will normally have higher throughput than a fair lock.
|
||||
*
|
||||
* <dt><b><i>Fair mode</i></b>
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* When constructed as fair, threads contend for entry using an
|
||||
* <dd>When constructed as fair, threads contend for entry using an
|
||||
* approximately arrival-order policy. When the currently held lock
|
||||
* is released, either the longest-waiting single writer thread will
|
||||
* be assigned the write lock, or if there is a group of reader threads
|
||||
|
@ -167,7 +167,8 @@ public class PKCS10 {
|
||||
// key and signature algorithm we found.
|
||||
//
|
||||
try {
|
||||
sig = Signature.getInstance(id.getName());
|
||||
sigAlg = id.getName();
|
||||
sig = Signature.getInstance(sigAlg);
|
||||
sig.initVerify(subjectPublicKeyInfo);
|
||||
sig.update(data);
|
||||
if (!sig.verify(sigData))
|
||||
@ -218,6 +219,7 @@ public class PKCS10 {
|
||||
signature.update(certificateRequestInfo, 0,
|
||||
certificateRequestInfo.length);
|
||||
sig = signature.sign();
|
||||
sigAlg = signature.getAlgorithm();
|
||||
|
||||
/*
|
||||
* Build guts of SIGNED macro
|
||||
@ -250,6 +252,11 @@ public class PKCS10 {
|
||||
public PublicKey getSubjectPublicKeyInfo()
|
||||
{ return subjectPublicKeyInfo; }
|
||||
|
||||
/**
|
||||
* Returns the signature algorithm.
|
||||
*/
|
||||
public String getSigAlg() { return sigAlg; }
|
||||
|
||||
/**
|
||||
* Returns the additional attributes requested.
|
||||
*/
|
||||
@ -348,6 +355,7 @@ public class PKCS10 {
|
||||
|
||||
private X500Name subject;
|
||||
private PublicKey subjectPublicKeyInfo;
|
||||
private String sigAlg;
|
||||
private PKCS10Attributes attributeSet;
|
||||
private byte[] encoded; // signed
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ import sun.security.util.Debug;
|
||||
|
||||
/**
|
||||
* BasicChecker is a PKIXCertPathChecker that checks the basic information
|
||||
* on a PKIX certificate, namely the signature, timestamp, and subject/issuer
|
||||
* on a PKIX certificate, namely the signature, validity, and subject/issuer
|
||||
* name chaining.
|
||||
*
|
||||
* @since 1.4
|
||||
@ -125,7 +125,7 @@ class BasicChecker extends PKIXCertPathChecker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the signature, timestamp, and subject/issuer name chaining
|
||||
* Performs the signature, validity, and subject/issuer name chaining
|
||||
* checks on the certificate using its internal state. This method does
|
||||
* not remove any critical extensions from the Collection.
|
||||
*
|
||||
@ -141,7 +141,7 @@ class BasicChecker extends PKIXCertPathChecker {
|
||||
X509Certificate currCert = (X509Certificate)cert;
|
||||
|
||||
if (!sigOnly) {
|
||||
verifyTimestamp(currCert);
|
||||
verifyValidity(currCert);
|
||||
verifyNameChaining(currCert);
|
||||
}
|
||||
verifySignature(currCert);
|
||||
@ -177,12 +177,12 @@ class BasicChecker extends PKIXCertPathChecker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to verify the timestamp on a certificate
|
||||
* Internal method to verify the validity on a certificate
|
||||
*/
|
||||
private void verifyTimestamp(X509Certificate cert)
|
||||
private void verifyValidity(X509Certificate cert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
String msg = "timestamp";
|
||||
String msg = "validity";
|
||||
if (debug != null)
|
||||
debug.println("---checking " + msg + ":" + date.toString() + "...");
|
||||
|
||||
|
@ -27,6 +27,7 @@ package sun.security.tools.keytool;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.CodeSigner;
|
||||
import java.security.CryptoPrimitive;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.MessageDigest;
|
||||
@ -156,6 +157,7 @@ public final class Main {
|
||||
private boolean protectedPath = false;
|
||||
private boolean srcprotectedPath = false;
|
||||
private boolean cacerts = false;
|
||||
private boolean nowarn = false;
|
||||
private CertificateFactory cf = null;
|
||||
private KeyStore caks = null; // "cacerts" keystore
|
||||
private char[] srcstorePass = null;
|
||||
@ -166,6 +168,16 @@ public final class Main {
|
||||
private List<String> ids = new ArrayList<>(); // used in GENCRL
|
||||
private List<String> v3ext = new ArrayList<>();
|
||||
|
||||
// Warnings on weak algorithms
|
||||
private List<String> weakWarnings = new ArrayList<>();
|
||||
|
||||
private static final DisabledAlgorithmConstraints DISABLED_CHECK =
|
||||
new DisabledAlgorithmConstraints(
|
||||
DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
|
||||
|
||||
private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
|
||||
.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
|
||||
|
||||
enum Command {
|
||||
CERTREQ("Generates.a.certificate.request",
|
||||
ALIAS, SIGALG, FILEOUT, KEYPASS, KEYSTORE, DNAME,
|
||||
@ -351,7 +363,7 @@ public final class Main {
|
||||
private static final String NONE = "NONE";
|
||||
private static final String P11KEYSTORE = "PKCS11";
|
||||
private static final String P12KEYSTORE = "PKCS12";
|
||||
private final String keyAlias = "mykey";
|
||||
private static final String keyAlias = "mykey";
|
||||
|
||||
// for i18n
|
||||
private static final java.util.ResourceBundle rb =
|
||||
@ -387,6 +399,7 @@ public final class Main {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
printWeakWarnings(false);
|
||||
for (char[] pass : passwords) {
|
||||
if (pass != null) {
|
||||
Arrays.fill(pass, ' ');
|
||||
@ -476,6 +489,8 @@ public final class Main {
|
||||
help = true;
|
||||
} else if (collator.compare(flags, "-conf") == 0) {
|
||||
i++;
|
||||
} else if (collator.compare(flags, "-nowarn") == 0) {
|
||||
nowarn = true;
|
||||
} else if (collator.compare(flags, "-keystore") == 0) {
|
||||
ksfname = args[++i];
|
||||
if (new File(ksfname).getCanonicalPath().equals(
|
||||
@ -1152,11 +1167,11 @@ public final class Main {
|
||||
} else if (command == LIST) {
|
||||
if (storePass == null
|
||||
&& !KeyStoreUtil.isWindowsKeyStore(storetype)) {
|
||||
printWarning();
|
||||
printNoIntegrityWarning();
|
||||
}
|
||||
|
||||
if (alias != null) {
|
||||
doPrintEntry(alias, out);
|
||||
doPrintEntry(rb.getString("the.certificate"), alias, out);
|
||||
} else {
|
||||
doPrintEntries(out);
|
||||
}
|
||||
@ -1253,6 +1268,12 @@ public final class Main {
|
||||
throws Exception {
|
||||
|
||||
|
||||
if (keyStore.containsAlias(alias) == false) {
|
||||
MessageFormat form = new MessageFormat
|
||||
(rb.getString("Alias.alias.does.not.exist"));
|
||||
Object[] source = {alias};
|
||||
throw new Exception(form.format(source));
|
||||
}
|
||||
Certificate signerCert = keyStore.getCertificate(alias);
|
||||
byte[] encoded = signerCert.getEncoded();
|
||||
X509CertImpl signerCertImpl = new X509CertImpl(encoded);
|
||||
@ -1306,6 +1327,8 @@ public final class Main {
|
||||
byte[] rawReq = Pem.decode(new String(sb));
|
||||
PKCS10 req = new PKCS10(rawReq);
|
||||
|
||||
checkWeak(rb.getString("the.certificate.request"), req);
|
||||
|
||||
info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo()));
|
||||
info.set(X509CertInfo.SUBJECT,
|
||||
dname==null?req.getSubjectName():new X500Name(dname));
|
||||
@ -1335,6 +1358,9 @@ public final class Main {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkWeak(rb.getString("the.issuer"), keyStore.getCertificateChain(alias));
|
||||
checkWeak(rb.getString("the.generated.certificate"), cert);
|
||||
}
|
||||
|
||||
private void doGenCRL(PrintStream out)
|
||||
@ -1385,6 +1411,7 @@ public final class Main {
|
||||
} else {
|
||||
out.write(crl.getEncodedInternal());
|
||||
}
|
||||
checkWeak(rb.getString("the.generated.crl"), crl, privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1431,6 +1458,8 @@ public final class Main {
|
||||
// Sign the request and base-64 encode it
|
||||
request.encodeAndSign(subject, signature);
|
||||
request.print(out);
|
||||
|
||||
checkWeak(rb.getString("the.generated.certificate.request"), request);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1454,7 +1483,7 @@ public final class Main {
|
||||
{
|
||||
if (storePass == null
|
||||
&& !KeyStoreUtil.isWindowsKeyStore(storetype)) {
|
||||
printWarning();
|
||||
printNoIntegrityWarning();
|
||||
}
|
||||
if (alias == null) {
|
||||
alias = keyAlias;
|
||||
@ -1474,6 +1503,7 @@ public final class Main {
|
||||
throw new Exception(form.format(source));
|
||||
}
|
||||
dumpCert(cert, out);
|
||||
checkWeak(rb.getString("the.certificate"), cert);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1729,6 +1759,8 @@ public final class Main {
|
||||
keyPass = promptForKeyPass(alias, null, storePass);
|
||||
}
|
||||
keyStore.setKeyEntry(alias, privKey, keyPass, chain);
|
||||
|
||||
checkWeak(rb.getString("the.generated.certificate"), chain[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1810,7 +1842,7 @@ public final class Main {
|
||||
/**
|
||||
* Prints a single keystore entry.
|
||||
*/
|
||||
private void doPrintEntry(String alias, PrintStream out)
|
||||
private void doPrintEntry(String label, String alias, PrintStream out)
|
||||
throws Exception
|
||||
{
|
||||
if (keyStore.containsAlias(alias) == false) {
|
||||
@ -1881,12 +1913,14 @@ public final class Main {
|
||||
} else {
|
||||
dumpCert(chain[i], out);
|
||||
}
|
||||
checkWeak(label, chain[i]);
|
||||
}
|
||||
} else {
|
||||
// Print the digest of the user cert only
|
||||
out.println
|
||||
(rb.getString("Certificate.fingerprint.SHA.256.") +
|
||||
getCertFingerPrint("SHA-256", chain[0]));
|
||||
checkWeak(label, chain);
|
||||
}
|
||||
}
|
||||
} else if (keyStore.entryInstanceOf(alias,
|
||||
@ -1909,6 +1943,7 @@ public final class Main {
|
||||
out.println(rb.getString("Certificate.fingerprint.SHA.256.")
|
||||
+ getCertFingerPrint("SHA-256", cert));
|
||||
}
|
||||
checkWeak(label, cert);
|
||||
} else {
|
||||
out.println(rb.getString("Unknown.Entry.Type"));
|
||||
}
|
||||
@ -1992,7 +2027,7 @@ public final class Main {
|
||||
|
||||
if (srcstorePass == null
|
||||
&& !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
|
||||
// anti refactoring, copied from printWarning(),
|
||||
// anti refactoring, copied from printNoIntegrityWarning(),
|
||||
// but change 2 lines
|
||||
System.err.println();
|
||||
System.err.println(rb.getString
|
||||
@ -2092,6 +2127,10 @@ public final class Main {
|
||||
"The.destination.pkcs12.keystore.has.different.storepass.and.keypass.Please.retry.with.destkeypass.specified."));
|
||||
}
|
||||
}
|
||||
Certificate c = srckeystore.getCertificate(alias);
|
||||
if (c != null) {
|
||||
checkWeak("<" + newAlias + ">", c);
|
||||
}
|
||||
return 1;
|
||||
} catch (KeyStoreException kse) {
|
||||
Object[] source2 = {alias, kse.toString()};
|
||||
@ -2154,7 +2193,7 @@ public final class Main {
|
||||
for (Enumeration<String> e = keyStore.aliases();
|
||||
e.hasMoreElements(); ) {
|
||||
String alias = e.nextElement();
|
||||
doPrintEntry(alias, out);
|
||||
doPrintEntry("<" + alias + ">", alias, out);
|
||||
if (verbose || rfc) {
|
||||
out.println(rb.getString("NEWLINE"));
|
||||
out.println(rb.getString
|
||||
@ -2300,19 +2339,28 @@ public final class Main {
|
||||
for (CRL crl: loadCRLs(src)) {
|
||||
printCRL(crl, out);
|
||||
String issuer = null;
|
||||
Certificate signer = null;
|
||||
if (caks != null) {
|
||||
issuer = verifyCRL(caks, crl);
|
||||
if (issuer != null) {
|
||||
signer = caks.getCertificate(issuer);
|
||||
out.printf(rb.getString(
|
||||
"verified.by.s.in.s"), issuer, "cacerts");
|
||||
"verified.by.s.in.s.weak"),
|
||||
issuer,
|
||||
"cacerts",
|
||||
withWeak(signer.getPublicKey()));
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
if (issuer == null && keyStore != null) {
|
||||
issuer = verifyCRL(keyStore, crl);
|
||||
if (issuer != null) {
|
||||
signer = keyStore.getCertificate(issuer);
|
||||
out.printf(rb.getString(
|
||||
"verified.by.s.in.s"), issuer, "keystore");
|
||||
"verified.by.s.in.s.weak"),
|
||||
issuer,
|
||||
"keystore",
|
||||
withWeak(signer.getPublicKey()));
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
@ -2324,18 +2372,26 @@ public final class Main {
|
||||
out.println(rb.getString
|
||||
("STARNN"));
|
||||
}
|
||||
checkWeak(rb.getString("the.crl"), crl, signer == null ? null : signer.getPublicKey());
|
||||
}
|
||||
}
|
||||
|
||||
private void printCRL(CRL crl, PrintStream out)
|
||||
throws Exception {
|
||||
X509CRL xcrl = (X509CRL)crl;
|
||||
if (rfc) {
|
||||
X509CRL xcrl = (X509CRL)crl;
|
||||
out.println("-----BEGIN X509 CRL-----");
|
||||
out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(xcrl.getEncoded()));
|
||||
out.println("-----END X509 CRL-----");
|
||||
} else {
|
||||
out.println(crl.toString());
|
||||
String s;
|
||||
if (crl instanceof X509CRLImpl) {
|
||||
X509CRLImpl x509crl = (X509CRLImpl) crl;
|
||||
s = x509crl.toStringWithAlgName(withWeak("" + x509crl.getSigAlgId()));
|
||||
} else {
|
||||
s = crl.toString();
|
||||
}
|
||||
out.println(s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2362,8 +2418,11 @@ public final class Main {
|
||||
PKCS10 req = new PKCS10(Pem.decode(new String(sb)));
|
||||
|
||||
PublicKey pkey = req.getSubjectPublicKeyInfo();
|
||||
out.printf(rb.getString("PKCS.10.Certificate.Request.Version.1.0.Subject.s.Public.Key.s.format.s.key."),
|
||||
req.getSubjectName(), pkey.getFormat(), pkey.getAlgorithm());
|
||||
out.printf(rb.getString("PKCS.10.with.weak"),
|
||||
req.getSubjectName(),
|
||||
pkey.getFormat(),
|
||||
withWeak(pkey),
|
||||
withWeak(req.getSigAlg()));
|
||||
for (PKCS10Attribute attr: req.getAttributes().getAttributes()) {
|
||||
ObjectIdentifier oid = attr.getAttributeId();
|
||||
if (oid.equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) {
|
||||
@ -2386,6 +2445,7 @@ public final class Main {
|
||||
if (debug) {
|
||||
out.println(req); // Just to see more, say, public key length...
|
||||
}
|
||||
checkWeak(rb.getString("the.certificate.request"), req);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2425,6 +2485,15 @@ public final class Main {
|
||||
if (i < (certs.length-1)) {
|
||||
out.println();
|
||||
}
|
||||
checkWeak(oneInMany(rb.getString("the.certificate"), i, certs.length), x509Cert);
|
||||
}
|
||||
}
|
||||
|
||||
private static String oneInMany(String label, int i, int num) {
|
||||
if (num == 1) {
|
||||
return label;
|
||||
} else {
|
||||
return String.format(rb.getString("one.in.many"), label, i+1, num);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2458,7 +2527,11 @@ public final class Main {
|
||||
out.println();
|
||||
out.println(rb.getString("Signature."));
|
||||
out.println();
|
||||
for (Certificate cert: signer.getSignerCertPath().getCertificates()) {
|
||||
|
||||
List<? extends Certificate> certs
|
||||
= signer.getSignerCertPath().getCertificates();
|
||||
int cc = 0;
|
||||
for (Certificate cert: certs) {
|
||||
X509Certificate x = (X509Certificate)cert;
|
||||
if (rfc) {
|
||||
out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
|
||||
@ -2467,12 +2540,15 @@ public final class Main {
|
||||
printX509Cert(x, out);
|
||||
}
|
||||
out.println();
|
||||
checkWeak(oneInMany(rb.getString("the.certificate"), cc++, certs.size()), x);
|
||||
}
|
||||
Timestamp ts = signer.getTimestamp();
|
||||
if (ts != null) {
|
||||
out.println(rb.getString("Timestamp."));
|
||||
out.println();
|
||||
for (Certificate cert: ts.getSignerCertPath().getCertificates()) {
|
||||
certs = ts.getSignerCertPath().getCertificates();
|
||||
cc = 0;
|
||||
for (Certificate cert: certs) {
|
||||
X509Certificate x = (X509Certificate)cert;
|
||||
if (rfc) {
|
||||
out.println(rb.getString("Certificate.owner.") + x.getSubjectDN() + "\n");
|
||||
@ -2481,6 +2557,7 @@ public final class Main {
|
||||
printX509Cert(x, out);
|
||||
}
|
||||
out.println();
|
||||
checkWeak(oneInMany(rb.getString("the.tsa.certificate"), cc++, certs.size()), x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2523,6 +2600,7 @@ public final class Main {
|
||||
printX509Cert((X509Certificate)cert, out);
|
||||
out.println();
|
||||
}
|
||||
checkWeak(oneInMany(rb.getString("the.certificate"), i, chain.size()), cert);
|
||||
} catch (Exception e) {
|
||||
if (debug) {
|
||||
e.printStackTrace();
|
||||
@ -2698,7 +2776,7 @@ public final class Main {
|
||||
}
|
||||
|
||||
// Now store the newly established chain in the keystore. The new
|
||||
// chain replaces the old one.
|
||||
// chain replaces the old one. The chain can be null if user chooses no.
|
||||
if (newChain != null) {
|
||||
keyStore.setKeyEntry(alias, privKey,
|
||||
(keyPass != null) ? keyPass : storePass,
|
||||
@ -2735,6 +2813,12 @@ public final class Main {
|
||||
throw new Exception(rb.getString("Input.not.an.X.509.certificate"));
|
||||
}
|
||||
|
||||
if (noprompt) {
|
||||
keyStore.setCertificateEntry(alias, cert);
|
||||
checkWeak(rb.getString("the.input"), cert);
|
||||
return true;
|
||||
}
|
||||
|
||||
// if certificate is self-signed, make sure it verifies
|
||||
boolean selfSigned = false;
|
||||
if (KeyStoreUtil.isSelfSigned(cert)) {
|
||||
@ -2742,11 +2826,6 @@ public final class Main {
|
||||
selfSigned = true;
|
||||
}
|
||||
|
||||
if (noprompt) {
|
||||
keyStore.setCertificateEntry(alias, cert);
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if cert already exists in keystore
|
||||
String reply = null;
|
||||
String trustalias = keyStore.getCertificateAlias(cert);
|
||||
@ -2755,6 +2834,8 @@ public final class Main {
|
||||
("Certificate.already.exists.in.keystore.under.alias.trustalias."));
|
||||
Object[] source = {trustalias};
|
||||
System.err.println(form.format(source));
|
||||
checkWeak(rb.getString("the.input"), cert);
|
||||
printWeakWarnings(true);
|
||||
reply = getYesNoReply
|
||||
(rb.getString("Do.you.still.want.to.add.it.no."));
|
||||
} else if (selfSigned) {
|
||||
@ -2764,6 +2845,8 @@ public final class Main {
|
||||
("Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias."));
|
||||
Object[] source = {trustalias};
|
||||
System.err.println(form.format(source));
|
||||
checkWeak(rb.getString("the.input"), cert);
|
||||
printWeakWarnings(true);
|
||||
reply = getYesNoReply
|
||||
(rb.getString("Do.you.still.want.to.add.it.to.your.own.keystore.no."));
|
||||
}
|
||||
@ -2771,6 +2854,8 @@ public final class Main {
|
||||
// Print the cert and ask user if they really want to add
|
||||
// it to their keystore
|
||||
printX509Cert(cert, System.out);
|
||||
checkWeak(rb.getString("the.input"), cert);
|
||||
printWeakWarnings(true);
|
||||
reply = getYesNoReply
|
||||
(rb.getString("Trust.this.certificate.no."));
|
||||
}
|
||||
@ -2784,6 +2869,7 @@ public final class Main {
|
||||
}
|
||||
}
|
||||
|
||||
// Not found in this keystore and not self-signed
|
||||
// Try to establish trust chain
|
||||
try {
|
||||
Certificate[] chain = establishCertChain(null, cert);
|
||||
@ -2795,6 +2881,8 @@ public final class Main {
|
||||
// Print the cert and ask user if they really want to add it to
|
||||
// their keystore
|
||||
printX509Cert(cert, System.out);
|
||||
checkWeak(rb.getString("the.input"), cert);
|
||||
printWeakWarnings(true);
|
||||
reply = getYesNoReply
|
||||
(rb.getString("Trust.this.certificate.no."));
|
||||
if ("YES".equals(reply)) {
|
||||
@ -2933,6 +3021,24 @@ public final class Main {
|
||||
return keyPass;
|
||||
}
|
||||
|
||||
private String withWeak(String alg) {
|
||||
if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) {
|
||||
return alg;
|
||||
} else {
|
||||
return String.format(rb.getString("with.weak"), alg);
|
||||
}
|
||||
}
|
||||
|
||||
private String withWeak(PublicKey key) {
|
||||
if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
|
||||
return String.format(rb.getString("key.bit"),
|
||||
KeyUtil.getKeySize(key), key.getAlgorithm());
|
||||
} else {
|
||||
return String.format(rb.getString("key.bit.weak"),
|
||||
KeyUtil.getKeySize(key), key.getAlgorithm());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a certificate in a human readable format.
|
||||
*/
|
||||
@ -2941,7 +3047,7 @@ public final class Main {
|
||||
{
|
||||
|
||||
MessageFormat form = new MessageFormat
|
||||
(rb.getString(".PATTERN.printX509Cert"));
|
||||
(rb.getString(".PATTERN.printX509Cert.with.weak"));
|
||||
PublicKey pkey = cert.getPublicKey();
|
||||
Object[] source = {cert.getSubjectDN().toString(),
|
||||
cert.getIssuerDN().toString(),
|
||||
@ -2950,10 +3056,9 @@ public final class Main {
|
||||
cert.getNotAfter().toString(),
|
||||
getCertFingerPrint("SHA-1", cert),
|
||||
getCertFingerPrint("SHA-256", cert),
|
||||
cert.getSigAlgName(),
|
||||
pkey.getAlgorithm(),
|
||||
KeyUtil.getKeySize(pkey),
|
||||
cert.getVersion(),
|
||||
withWeak(cert.getSigAlgName()),
|
||||
withWeak(pkey),
|
||||
cert.getVersion()
|
||||
};
|
||||
out.println(form.format(source));
|
||||
|
||||
@ -3003,12 +3108,12 @@ public final class Main {
|
||||
* @param ks the keystore to search with, not null
|
||||
* @return <code>cert</code> itself if it's already inside <code>ks</code>,
|
||||
* or a certificate inside <code>ks</code> who signs <code>cert</code>,
|
||||
* or null otherwise.
|
||||
* or null otherwise. A label is added.
|
||||
*/
|
||||
private static Certificate getTrustedSigner(Certificate cert, KeyStore ks)
|
||||
throws Exception {
|
||||
private static Pair<String,Certificate>
|
||||
getTrustedSigner(Certificate cert, KeyStore ks) throws Exception {
|
||||
if (ks.getCertificateAlias(cert) != null) {
|
||||
return cert;
|
||||
return new Pair<>("", cert);
|
||||
}
|
||||
for (Enumeration<String> aliases = ks.aliases();
|
||||
aliases.hasMoreElements(); ) {
|
||||
@ -3017,7 +3122,7 @@ public final class Main {
|
||||
if (trustedCert != null) {
|
||||
try {
|
||||
cert.verify(trustedCert.getPublicKey());
|
||||
return trustedCert;
|
||||
return new Pair<>(name, trustedCert);
|
||||
} catch (Exception e) {
|
||||
// Not verified, skip to the next one
|
||||
}
|
||||
@ -3281,7 +3386,7 @@ public final class Main {
|
||||
/**
|
||||
* Prints warning about missing integrity check.
|
||||
*/
|
||||
private void printWarning() {
|
||||
private void printNoIntegrityWarning() {
|
||||
System.err.println();
|
||||
System.err.println(rb.getString
|
||||
(".WARNING.WARNING.WARNING."));
|
||||
@ -3306,6 +3411,9 @@ public final class Main {
|
||||
Certificate[] replyCerts)
|
||||
throws Exception
|
||||
{
|
||||
|
||||
checkWeak(rb.getString("reply"), replyCerts);
|
||||
|
||||
// order the certs in the reply (bottom-up).
|
||||
// we know that all certs in the reply are of type X.509, because
|
||||
// we parsed them using an X.509 certificate factory
|
||||
@ -3358,9 +3466,11 @@ public final class Main {
|
||||
|
||||
// do we trust the cert at the top?
|
||||
Certificate topCert = replyCerts[replyCerts.length-1];
|
||||
Certificate root = getTrustedSigner(topCert, keyStore);
|
||||
boolean fromKeyStore = true;
|
||||
Pair<String,Certificate> root = getTrustedSigner(topCert, keyStore);
|
||||
if (root == null && trustcacerts && caks != null) {
|
||||
root = getTrustedSigner(topCert, caks);
|
||||
fromKeyStore = false;
|
||||
}
|
||||
if (root == null) {
|
||||
System.err.println();
|
||||
@ -3369,33 +3479,42 @@ public final class Main {
|
||||
printX509Cert((X509Certificate)topCert, System.out);
|
||||
System.err.println();
|
||||
System.err.print(rb.getString(".is.not.trusted."));
|
||||
printWeakWarnings(true);
|
||||
String reply = getYesNoReply
|
||||
(rb.getString("Install.reply.anyway.no."));
|
||||
if ("NO".equals(reply)) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (root != topCert) {
|
||||
if (root.snd != topCert) {
|
||||
// append the root CA cert to the chain
|
||||
Certificate[] tmpCerts =
|
||||
new Certificate[replyCerts.length+1];
|
||||
System.arraycopy(replyCerts, 0, tmpCerts, 0,
|
||||
replyCerts.length);
|
||||
tmpCerts[tmpCerts.length-1] = root;
|
||||
tmpCerts[tmpCerts.length-1] = root.snd;
|
||||
replyCerts = tmpCerts;
|
||||
checkWeak(String.format(rb.getString(fromKeyStore ?
|
||||
"alias.in.keystore" :
|
||||
"alias.in.cacerts"),
|
||||
root.fst),
|
||||
root.snd);
|
||||
}
|
||||
}
|
||||
|
||||
return replyCerts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a certificate chain (using trusted certificates in the
|
||||
* keystore), starting with the user certificate
|
||||
* keystore and cacerts), starting with the reply (certToVerify)
|
||||
* and ending at a self-signed certificate found in the keystore.
|
||||
*
|
||||
* @param userCert the user certificate of the alias
|
||||
* @param certToVerify the single certificate provided in the reply
|
||||
* @param userCert optional existing certificate, mostly likely be the
|
||||
* original self-signed cert created by -genkeypair.
|
||||
* It must have the same public key as certToVerify
|
||||
* but cannot be the same cert.
|
||||
* @param certToVerify the starting certificate to build the chain
|
||||
* @returns the established chain, might be null if user decides not
|
||||
*/
|
||||
private Certificate[] establishCertChain(Certificate userCert,
|
||||
Certificate certToVerify)
|
||||
@ -3423,30 +3542,37 @@ public final class Main {
|
||||
// Use the subject distinguished name as the key into the hash table.
|
||||
// All certificates associated with the same subject distinguished
|
||||
// name are stored in the same hash table entry as a vector.
|
||||
Hashtable<Principal, Vector<Certificate>> certs = null;
|
||||
Hashtable<Principal, Vector<Pair<String,X509Certificate>>> certs = null;
|
||||
if (keyStore.size() > 0) {
|
||||
certs = new Hashtable<Principal, Vector<Certificate>>(11);
|
||||
certs = new Hashtable<>(11);
|
||||
keystorecerts2Hashtable(keyStore, certs);
|
||||
}
|
||||
if (trustcacerts) {
|
||||
if (caks!=null && caks.size()>0) {
|
||||
if (certs == null) {
|
||||
certs = new Hashtable<Principal, Vector<Certificate>>(11);
|
||||
certs = new Hashtable<>(11);
|
||||
}
|
||||
keystorecerts2Hashtable(caks, certs);
|
||||
}
|
||||
}
|
||||
|
||||
// start building chain
|
||||
Vector<Certificate> chain = new Vector<>(2);
|
||||
if (buildChain((X509Certificate)certToVerify, chain, certs)) {
|
||||
Certificate[] newChain = new Certificate[chain.size()];
|
||||
Vector<Pair<String,X509Certificate>> chain = new Vector<>(2);
|
||||
if (buildChain(
|
||||
new Pair<>(rb.getString("the.input"),
|
||||
(X509Certificate) certToVerify),
|
||||
chain, certs)) {
|
||||
for (Pair<String,X509Certificate> p : chain) {
|
||||
checkWeak(p.fst, p.snd);
|
||||
}
|
||||
Certificate[] newChain =
|
||||
new Certificate[chain.size()];
|
||||
// buildChain() returns chain with self-signed root-cert first and
|
||||
// user-cert last, so we need to invert the chain before we store
|
||||
// it
|
||||
int j=0;
|
||||
for (int i=chain.size()-1; i>=0; i--) {
|
||||
newChain[j] = chain.elementAt(i);
|
||||
newChain[j] = chain.elementAt(i).snd;
|
||||
j++;
|
||||
}
|
||||
return newChain;
|
||||
@ -3457,7 +3583,17 @@ public final class Main {
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively tries to establish chain from pool of trusted certs.
|
||||
* Recursively tries to establish chain from pool of certs starting from
|
||||
* certToVerify until a self-signed cert is found, and fill the certs found
|
||||
* into chain. Each cert in the chain signs the next one.
|
||||
*
|
||||
* This method is able to recover from an error, say, if certToVerify
|
||||
* is signed by certA but certA has no issuer in certs and itself is not
|
||||
* self-signed, the method can try another certB that also signs
|
||||
* certToVerify and look for signer of certB, etc, etc.
|
||||
*
|
||||
* Each cert in chain comes with a label showing its origin. The label is
|
||||
* used in the warning message when the cert is considered a risk.
|
||||
*
|
||||
* @param certToVerify the cert that needs to be verified.
|
||||
* @param chain the chain that's being built.
|
||||
@ -3465,19 +3601,20 @@ public final class Main {
|
||||
*
|
||||
* @return true if successful, false otherwise.
|
||||
*/
|
||||
private boolean buildChain(X509Certificate certToVerify,
|
||||
Vector<Certificate> chain,
|
||||
Hashtable<Principal, Vector<Certificate>> certs) {
|
||||
Principal issuer = certToVerify.getIssuerDN();
|
||||
if (KeyStoreUtil.isSelfSigned(certToVerify)) {
|
||||
private boolean buildChain(Pair<String,X509Certificate> certToVerify,
|
||||
Vector<Pair<String,X509Certificate>> chain,
|
||||
Hashtable<Principal, Vector<Pair<String,X509Certificate>>> certs) {
|
||||
if (KeyStoreUtil.isSelfSigned(certToVerify.snd)) {
|
||||
// reached self-signed root cert;
|
||||
// no verification needed because it's trusted.
|
||||
chain.addElement(certToVerify);
|
||||
return true;
|
||||
}
|
||||
|
||||
Principal issuer = certToVerify.snd.getIssuerDN();
|
||||
|
||||
// Get the issuer's certificate(s)
|
||||
Vector<Certificate> vec = certs.get(issuer);
|
||||
Vector<Pair<String,X509Certificate>> vec = certs.get(issuer);
|
||||
if (vec == null) {
|
||||
return false;
|
||||
}
|
||||
@ -3485,13 +3622,12 @@ public final class Main {
|
||||
// Try out each certificate in the vector, until we find one
|
||||
// whose public key verifies the signature of the certificate
|
||||
// in question.
|
||||
for (Enumeration<Certificate> issuerCerts = vec.elements();
|
||||
issuerCerts.hasMoreElements(); ) {
|
||||
X509Certificate issuerCert
|
||||
= (X509Certificate)issuerCerts.nextElement();
|
||||
PublicKey issuerPubKey = issuerCert.getPublicKey();
|
||||
for (Enumeration<Pair<String,X509Certificate>> issuerCerts = vec.elements();
|
||||
issuerCerts.hasMoreElements(); ) {
|
||||
Pair<String,X509Certificate> issuerCert = issuerCerts.nextElement();
|
||||
PublicKey issuerPubKey = issuerCert.snd.getPublicKey();
|
||||
try {
|
||||
certToVerify.verify(issuerPubKey);
|
||||
certToVerify.snd.verify(issuerPubKey);
|
||||
} catch (Exception e) {
|
||||
continue;
|
||||
}
|
||||
@ -3541,10 +3677,11 @@ public final class Main {
|
||||
/**
|
||||
* Stores the (leaf) certificates of a keystore in a hashtable.
|
||||
* All certs belonging to the same CA are stored in a vector that
|
||||
* in turn is stored in the hashtable, keyed by the CA's subject DN
|
||||
* in turn is stored in the hashtable, keyed by the CA's subject DN.
|
||||
* Each cert comes with a string label that shows its origin and alias.
|
||||
*/
|
||||
private void keystorecerts2Hashtable(KeyStore ks,
|
||||
Hashtable<Principal, Vector<Certificate>> hash)
|
||||
Hashtable<Principal, Vector<Pair<String,X509Certificate>>> hash)
|
||||
throws Exception {
|
||||
|
||||
for (Enumeration<String> aliases = ks.aliases();
|
||||
@ -3553,13 +3690,20 @@ public final class Main {
|
||||
Certificate cert = ks.getCertificate(alias);
|
||||
if (cert != null) {
|
||||
Principal subjectDN = ((X509Certificate)cert).getSubjectDN();
|
||||
Vector<Certificate> vec = hash.get(subjectDN);
|
||||
Pair<String,X509Certificate> pair = new Pair<>(
|
||||
String.format(
|
||||
rb.getString(ks == caks ?
|
||||
"alias.in.cacerts" :
|
||||
"alias.in.keystore"),
|
||||
alias),
|
||||
(X509Certificate)cert);
|
||||
Vector<Pair<String,X509Certificate>> vec = hash.get(subjectDN);
|
||||
if (vec == null) {
|
||||
vec = new Vector<Certificate>();
|
||||
vec.addElement(cert);
|
||||
vec = new Vector<>();
|
||||
vec.addElement(pair);
|
||||
} else {
|
||||
if (!vec.contains(cert)) {
|
||||
vec.addElement(cert);
|
||||
if (!vec.contains(pair)) {
|
||||
vec.addElement(pair);
|
||||
}
|
||||
}
|
||||
hash.put(subjectDN, vec);
|
||||
@ -4157,6 +4301,67 @@ public final class Main {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void checkWeak(String label, String sigAlg, Key key) {
|
||||
|
||||
if (!DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, sigAlg, null)) {
|
||||
weakWarnings.add(String.format(
|
||||
rb.getString("whose.sigalg.risk"), label, sigAlg));
|
||||
}
|
||||
if (key != null && !DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
|
||||
weakWarnings.add(String.format(
|
||||
rb.getString("whose.key.risk"),
|
||||
label,
|
||||
String.format(rb.getString("key.bit"),
|
||||
KeyUtil.getKeySize(key), key.getAlgorithm())));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkWeak(String label, Certificate[] certs) {
|
||||
for (int i = 0; i < certs.length; i++) {
|
||||
Certificate cert = certs[i];
|
||||
if (cert instanceof X509Certificate) {
|
||||
X509Certificate xc = (X509Certificate)cert;
|
||||
String fullLabel = label;
|
||||
if (certs.length > 1) {
|
||||
fullLabel = oneInMany(label, i, certs.length);
|
||||
}
|
||||
checkWeak(fullLabel, xc.getSigAlgName(), xc.getPublicKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkWeak(String label, Certificate cert) {
|
||||
if (cert instanceof X509Certificate) {
|
||||
X509Certificate xc = (X509Certificate)cert;
|
||||
checkWeak(label, xc.getSigAlgName(), xc.getPublicKey());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkWeak(String label, PKCS10 p10) {
|
||||
checkWeak(label, p10.getSigAlg(), p10.getSubjectPublicKeyInfo());
|
||||
}
|
||||
|
||||
private void checkWeak(String label, CRL crl, Key key) {
|
||||
if (crl instanceof X509CRLImpl) {
|
||||
X509CRLImpl impl = (X509CRLImpl)crl;
|
||||
checkWeak(label, impl.getSigAlgName(), key);
|
||||
}
|
||||
}
|
||||
|
||||
private void printWeakWarnings(boolean newLine) {
|
||||
if (!weakWarnings.isEmpty() && !nowarn) {
|
||||
System.err.println("\nWarning:");
|
||||
for (String warning : weakWarnings) {
|
||||
System.err.println(warning);
|
||||
}
|
||||
if (newLine) {
|
||||
// When calling before a yes/no prompt, add a new line
|
||||
System.err.println();
|
||||
}
|
||||
}
|
||||
weakWarnings.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the usage of this tool.
|
||||
*/
|
||||
|
@ -360,8 +360,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||
{"Enter.alias.name.", "Enter alias name: "},
|
||||
{".RETURN.if.same.as.for.otherAlias.",
|
||||
"\t(RETURN if same as for <{0}>)"},
|
||||
{".PATTERN.printX509Cert",
|
||||
"Owner: {0}\nIssuer: {1}\nSerial number: {2}\nValid from: {3} until: {4}\nCertificate fingerprints:\n\t SHA1: {5}\n\t SHA256: {6}\nSignature algorithm name: {7}\nSubject Public Key Algorithm: {8} ({9,number,#})\nVersion: {10}"},
|
||||
{"What.is.your.first.and.last.name.",
|
||||
"What is your first and last name?"},
|
||||
{"What.is.the.name.of.your.organizational.unit.",
|
||||
@ -428,16 +426,12 @@ public class Resources extends java.util.ListResourceBundle {
|
||||
{"Please.provide.keysize.for.secret.key.generation",
|
||||
"Please provide -keysize for secret key generation"},
|
||||
|
||||
{"verified.by.s.in.s", "Verified by %s in %s"},
|
||||
{"warning.not.verified.make.sure.keystore.is.correct",
|
||||
"WARNING: not verified. Make sure -keystore is correct."},
|
||||
|
||||
{"Extensions.", "Extensions: "},
|
||||
{".Empty.value.", "(Empty value)"},
|
||||
{"Extension.Request.", "Extension Request:"},
|
||||
{"PKCS.10.Certificate.Request.Version.1.0.Subject.s.Public.Key.s.format.s.key.",
|
||||
"PKCS #10 Certificate Request (Version 1.0)\n" +
|
||||
"Subject: %s\nPublic Key: %s format %s key\n"},
|
||||
{"Unknown.keyUsage.type.", "Unknown keyUsage type: "},
|
||||
{"Unknown.extendedkeyUsage.type.", "Unknown extendedkeyUsage type: "},
|
||||
{"Unknown.AccessDescription.type.", "Unknown AccessDescription type: "},
|
||||
@ -446,7 +440,34 @@ public class Resources extends java.util.ListResourceBundle {
|
||||
"This extension cannot be marked as critical. "},
|
||||
{"Odd.number.of.hex.digits.found.", "Odd number of hex digits found: "},
|
||||
{"Unknown.extension.type.", "Unknown extension type: "},
|
||||
{"command.{0}.is.ambiguous.", "command {0} is ambiguous:"}
|
||||
{"command.{0}.is.ambiguous.", "command {0} is ambiguous:"},
|
||||
|
||||
// 8171319: keytool should print out warnings when reading or
|
||||
// generating cert/cert req using weak algorithms
|
||||
{"the.certificate.request", "The certificate request"},
|
||||
{"the.issuer", "The issuer"},
|
||||
{"the.generated.certificate", "The generated certificate"},
|
||||
{"the.generated.crl", "The generated CRL"},
|
||||
{"the.generated.certificate.request", "The generated certificate request"},
|
||||
{"the.certificate", "The certificate"},
|
||||
{"the.crl", "The CRL"},
|
||||
{"the.tsa.certificate", "The TSA certificate"},
|
||||
{"the.input", "The input"},
|
||||
{"reply", "Reply"},
|
||||
{"one.in.many", "%s #%d of %d"},
|
||||
{"alias.in.cacerts", "Issuer <%s> in cacerts"},
|
||||
{"alias.in.keystore", "Issuer <%s>"},
|
||||
{"with.weak", "%s (weak)"},
|
||||
{"key.bit", "%d-bit %s key"},
|
||||
{"key.bit.weak", "%d-bit %s key (weak)"},
|
||||
{".PATTERN.printX509Cert.with.weak",
|
||||
"Owner: {0}\nIssuer: {1}\nSerial number: {2}\nValid from: {3} until: {4}\nCertificate fingerprints:\n\t SHA1: {5}\n\t SHA256: {6}\nSignature algorithm name: {7}\nSubject Public Key Algorithm: {8}\nVersion: {9}"},
|
||||
{"PKCS.10.with.weak",
|
||||
"PKCS #10 Certificate Request (Version 1.0)\n" +
|
||||
"Subject: %s\nFormat: %s\nPublic Key: %s\nSignature algorithm: %s\n"},
|
||||
{"verified.by.s.in.s.weak", "Verified by %s in %s with a %s"},
|
||||
{"whose.sigalg.risk", "%s uses the %s signature algorithm which is considered a security risk."},
|
||||
{"whose.key.risk", "%s uses a %s which is considered a security risk."},
|
||||
};
|
||||
|
||||
|
||||
|
@ -536,13 +536,18 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
|
||||
* @return value of this CRL in a printable form.
|
||||
*/
|
||||
public String toString() {
|
||||
return toStringWithAlgName("" + sigAlgId);
|
||||
}
|
||||
|
||||
// Specifically created for keytool to append a (weak) label to sigAlg
|
||||
public String toStringWithAlgName(String name) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("X.509 CRL v")
|
||||
.append(version+1)
|
||||
.append('\n');
|
||||
if (sigAlgId != null)
|
||||
sb.append("Signature Algorithm: ")
|
||||
.append(sigAlgId)
|
||||
.append(name)
|
||||
.append(", OID=")
|
||||
.append(sigAlgId.getOID())
|
||||
.append('\n');
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2017, 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
|
||||
@ -332,7 +332,7 @@ const char * isJar(const char * path) {
|
||||
|
||||
if (end <= count) {
|
||||
end -= 4; // make sure there are 4 bytes to read at start
|
||||
while (start < end) {
|
||||
while (start <= end) {
|
||||
off_t xhid = SH(buf, start);
|
||||
off_t xdlen = SH(buf, start + 2);
|
||||
|
||||
|
@ -23,6 +23,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The SunPKCS11 security provider.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
module jdk.crypto.cryptoki {
|
||||
// Depends on SunEC provider for EC related functionality
|
||||
requires jdk.crypto.ec;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, 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,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The SunEC security provider.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
module jdk.crypto.ec {
|
||||
provides java.security.Provider with sun.security.ec.SunEC;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, 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,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The SunMSCAPI security provider.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
module jdk.crypto.mscapi {
|
||||
provides java.security.Provider with sun.security.mscapi.SunMSCAPI;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, 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,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The OracleUCrypto security provider.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
module jdk.crypto.ucrypto {
|
||||
provides java.security.Provider with com.oracle.security.ucrypto.UcryptoProvider;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, 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,14 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GUI tool for managing policy files.
|
||||
*
|
||||
* @since 9
|
||||
* @deprecated The policytool tool has been deprecated and
|
||||
* is planned to be removed in a future release.
|
||||
*/
|
||||
@Deprecated
|
||||
module jdk.policytool {
|
||||
requires java.desktop;
|
||||
requires java.logging;
|
||||
|
@ -125,6 +125,8 @@ java/beans/Introspector/8132566/OverrideUserDefPropertyInfoTest.java 8132565 gen
|
||||
|
||||
java/lang/StringCoding/CheckEncodings.sh 7008363 generic-all
|
||||
|
||||
jdk/internal/misc/JavaLangAccess/NewUnsafeString.java 8176188 generic-all
|
||||
|
||||
############################################################################
|
||||
|
||||
# jdk_instrument
|
||||
@ -215,6 +217,10 @@ sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java 8026393 generic-
|
||||
javax/net/ssl/DTLS/PacketLossRetransmission.java 8169086 macosx-x64
|
||||
javax/net/ssl/DTLS/RespondToRetransmit.java 8169086 macosx-x64
|
||||
|
||||
sun/security/mscapi/SignedObjectChain.java 8176183 windows-all
|
||||
|
||||
sun/security/krb5/auto/Basic.java 8176296 generic-all
|
||||
|
||||
############################################################################
|
||||
|
||||
# jdk_sound
|
||||
|
@ -26,7 +26,9 @@
|
||||
* @bug 8035105
|
||||
* @summary DNS resource record parsing
|
||||
* @modules jdk.naming.dns/com.sun.jndi.dns:+open
|
||||
*
|
||||
* @compile --add-modules jdk.naming.dns Parser.java
|
||||
* @run main Parser
|
||||
*/
|
||||
|
||||
import com.sun.jndi.dns.ResourceRecord;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, 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
|
||||
@ -27,6 +27,7 @@
|
||||
* @summary Make sure that "UTC" is an alias of "Etc/UTC" as defined in the tzdata backward.
|
||||
* @modules java.base/sun.util.calendar
|
||||
* @compile -XDignore.symbol.file UTCAliasTest.java
|
||||
* @run main UTCAliasTest
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
|
@ -1,755 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Written by Martin Buchholz with assistance from members of JCP
|
||||
* JSR-166 Expert Group and released to the public domain, as
|
||||
* explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7014263
|
||||
* @modules java.base/java.util.concurrent:open
|
||||
* @summary White box testing of ArrayBlockingQueue iterators.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tightly coupled to the implementation of ArrayBlockingQueue.
|
||||
* Uses reflection to inspect queue and iterator state.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class IteratorConsistency {
|
||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||
final int CAPACITY = 20;
|
||||
Field itrsField;
|
||||
Field itemsField;
|
||||
Field takeIndexField;
|
||||
Field headField;
|
||||
Field nextField;
|
||||
Field prevTakeIndexField;
|
||||
|
||||
void test(String[] args) throws Throwable {
|
||||
itrsField = ArrayBlockingQueue.class.getDeclaredField("itrs");
|
||||
itemsField = ArrayBlockingQueue.class.getDeclaredField("items");
|
||||
takeIndexField = ArrayBlockingQueue.class.getDeclaredField("takeIndex");
|
||||
headField = Class.forName("java.util.concurrent.ArrayBlockingQueue$Itrs").getDeclaredField("head");
|
||||
nextField = Class.forName("java.util.concurrent.ArrayBlockingQueue$Itrs$Node").getDeclaredField("next");
|
||||
prevTakeIndexField = Class.forName("java.util.concurrent.ArrayBlockingQueue$Itr").getDeclaredField("prevTakeIndex");
|
||||
itrsField.setAccessible(true);
|
||||
itemsField.setAccessible(true);
|
||||
takeIndexField.setAccessible(true);
|
||||
headField.setAccessible(true);
|
||||
nextField.setAccessible(true);
|
||||
prevTakeIndexField.setAccessible(true);
|
||||
test(CAPACITY, true);
|
||||
test(CAPACITY, false);
|
||||
}
|
||||
|
||||
Object itrs(ArrayBlockingQueue q) {
|
||||
try { return itrsField.get(q); }
|
||||
catch (Throwable ex) { throw new AssertionError(ex); }
|
||||
}
|
||||
|
||||
int takeIndex(ArrayBlockingQueue q) {
|
||||
try { return takeIndexField.getInt(q); }
|
||||
catch (Throwable ex) { throw new AssertionError(ex); }
|
||||
}
|
||||
|
||||
List<Iterator> trackedIterators(Object itrs) {
|
||||
try {
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
if (itrs != null)
|
||||
for (Object p = headField.get(itrs); p != null; p = nextField.get(p))
|
||||
its.add(((WeakReference<Iterator>)(p)).get());
|
||||
Collections.reverse(its);
|
||||
return its;
|
||||
} catch (Throwable ex) { throw new AssertionError(ex); }
|
||||
}
|
||||
|
||||
List<Iterator> trackedIterators(ArrayBlockingQueue q) {
|
||||
return trackedIterators(itrs(q));
|
||||
}
|
||||
|
||||
List<Iterator> attachedIterators(Object itrs) {
|
||||
try {
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
if (itrs != null)
|
||||
for (Object p = headField.get(itrs); p != null; p = nextField.get(p)) {
|
||||
Iterator it = ((WeakReference<Iterator>)(p)).get();
|
||||
if (it != null && !isDetached(it))
|
||||
its.add(it);
|
||||
}
|
||||
Collections.reverse(its);
|
||||
return its;
|
||||
} catch (Throwable ex) { unexpected(ex); return null; }
|
||||
}
|
||||
|
||||
List<Iterator> attachedIterators(ArrayBlockingQueue q) {
|
||||
return attachedIterators(itrs(q));
|
||||
}
|
||||
|
||||
Object[] internalArray(ArrayBlockingQueue q) {
|
||||
try { return (Object[]) itemsField.get(q); }
|
||||
catch (Throwable ex) { throw new AssertionError(ex); }
|
||||
}
|
||||
|
||||
void printInternalArray(ArrayBlockingQueue q) {
|
||||
System.err.println(Arrays.toString(internalArray(q)));
|
||||
}
|
||||
|
||||
void checkExhausted(Iterator it) {
|
||||
if (rnd.nextBoolean()) {
|
||||
check(!it.hasNext());
|
||||
check(isDetached(it));
|
||||
}
|
||||
if (rnd.nextBoolean()) {
|
||||
it.forEachRemaining(e -> { throw new AssertionError(); });
|
||||
checkDetached(it);
|
||||
}
|
||||
if (rnd.nextBoolean())
|
||||
try { it.next(); fail("should throw"); }
|
||||
catch (NoSuchElementException success) {}
|
||||
}
|
||||
|
||||
boolean isDetached(Iterator it) {
|
||||
try {
|
||||
return prevTakeIndexField.getInt(it) < 0;
|
||||
} catch (IllegalAccessException t) { unexpected(t); return false; }
|
||||
}
|
||||
|
||||
void checkDetached(Iterator it) {
|
||||
check(isDetached(it));
|
||||
}
|
||||
|
||||
void removeUsingIterator(ArrayBlockingQueue q, Object element) {
|
||||
Iterator it = q.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object x = it.next();
|
||||
if (element.equals(x))
|
||||
it.remove();
|
||||
checkRemoveThrowsISE(it);
|
||||
}
|
||||
}
|
||||
|
||||
void checkRemoveThrowsISE(Iterator it) {
|
||||
if (rnd.nextBoolean())
|
||||
return;
|
||||
try { it.remove(); fail("should throw"); }
|
||||
catch (IllegalStateException success) {}
|
||||
}
|
||||
|
||||
void checkRemoveHasNoEffect(Iterator it, Collection c) {
|
||||
if (rnd.nextBoolean())
|
||||
return;
|
||||
int size = c.size();
|
||||
it.remove(); // no effect
|
||||
equal(c.size(), size);
|
||||
checkRemoveThrowsISE(it);
|
||||
}
|
||||
|
||||
void checkIterationSanity(Queue q) {
|
||||
if (rnd.nextBoolean())
|
||||
return;
|
||||
int size = q.size();
|
||||
Object[] a = q.toArray();
|
||||
Object[] b = new Object[size+2];
|
||||
Arrays.fill(b, Boolean.TRUE);
|
||||
Object[] c = q.toArray(b);
|
||||
equal(a.length, size);
|
||||
check(b == c);
|
||||
check(b[size] == null);
|
||||
check(b[size+1] == Boolean.TRUE);
|
||||
equal(q.toString(), Arrays.toString(a));
|
||||
Integer[] xx = null, yy = null;
|
||||
if (size > 0) {
|
||||
xx = new Integer[size - 1];
|
||||
Arrays.fill(xx, 42);
|
||||
yy = ((Queue<Integer>)q).toArray(xx);
|
||||
for (Integer zz : xx)
|
||||
equal(42, zz);
|
||||
}
|
||||
Iterator it = q.iterator();
|
||||
for (int i = 0; i < size; i++) {
|
||||
check(it.hasNext());
|
||||
Object x = it.next();
|
||||
check(x == a[i]);
|
||||
check(x == b[i]);
|
||||
if (xx != null) check(x == yy[i]);
|
||||
}
|
||||
check(!it.hasNext());
|
||||
}
|
||||
|
||||
private static void waitForFinalizersToRun() {
|
||||
for (int i = 0; i < 2; i++)
|
||||
tryWaitForFinalizersToRun();
|
||||
}
|
||||
|
||||
private static void tryWaitForFinalizersToRun() {
|
||||
System.gc();
|
||||
final CountDownLatch fin = new CountDownLatch(1);
|
||||
new Object() { protected void finalize() { fin.countDown(); }};
|
||||
System.gc();
|
||||
try { fin.await(); }
|
||||
catch (InterruptedException ie) { throw new Error(ie); }
|
||||
}
|
||||
|
||||
void test(int capacity, boolean fair) {
|
||||
//----------------------------------------------------------------
|
||||
// q.clear will clear out itrs.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
check(q.add(i));
|
||||
check(itrs(q) == null);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
its.add(q.iterator());
|
||||
equal(trackedIterators(q), its);
|
||||
q.poll();
|
||||
q.add(capacity+i);
|
||||
}
|
||||
q.clear();
|
||||
check(itrs(q) == null);
|
||||
int j = 0;
|
||||
for (Iterator it : its) {
|
||||
if (rnd.nextBoolean())
|
||||
check(it.hasNext());
|
||||
equal(it.next(), j++);
|
||||
checkExhausted(it);
|
||||
}
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// q emptying will clear out itrs.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
check(itrs(q) == null);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
its.add(q.iterator());
|
||||
equal(trackedIterators(q), its);
|
||||
q.poll();
|
||||
q.add(capacity+i);
|
||||
}
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.poll();
|
||||
check(itrs(q) == null);
|
||||
int j = 0;
|
||||
for (Iterator it : its) {
|
||||
if (rnd.nextBoolean())
|
||||
check(it.hasNext());
|
||||
equal(it.next(), j++);
|
||||
checkExhausted(it);
|
||||
}
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Advancing 2 cycles will remove iterators.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
check(itrs(q) == null);
|
||||
for (int i = capacity; i < 3 * capacity; i++) {
|
||||
its.add(q.iterator());
|
||||
equal(trackedIterators(q), its);
|
||||
q.poll();
|
||||
q.add(i);
|
||||
}
|
||||
for (int i = 3 * capacity; i < 4 * capacity; i++) {
|
||||
equal(trackedIterators(q), its.subList(capacity,2*capacity));
|
||||
q.poll();
|
||||
q.add(i);
|
||||
}
|
||||
check(itrs(q) == null);
|
||||
int j = 0;
|
||||
for (Iterator it : its) {
|
||||
if (rnd.nextBoolean())
|
||||
check(it.hasNext());
|
||||
equal(it.next(), j++);
|
||||
checkExhausted(it);
|
||||
}
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Interior removal of elements used by an iterator will cause
|
||||
// it to be untracked.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
q.add(0);
|
||||
for (int i = 1; i < 2 * capacity; i++) {
|
||||
q.add(i);
|
||||
Integer[] elts = { -1, -2, -3 };
|
||||
for (Integer elt : elts) q.add(elt);
|
||||
equal(q.remove(), i - 1);
|
||||
Iterator it = q.iterator();
|
||||
equal(it.next(), i);
|
||||
equal(it.next(), elts[0]);
|
||||
Collections.shuffle(Arrays.asList(elts));
|
||||
check(q.remove(elts[0]));
|
||||
check(q.remove(elts[1]));
|
||||
equal(trackedIterators(q), Collections.singletonList(it));
|
||||
check(q.remove(elts[2]));
|
||||
check(itrs(q) == null);
|
||||
equal(it.next(), -2);
|
||||
if (rnd.nextBoolean()) checkExhausted(it);
|
||||
if (rnd.nextBoolean()) checkDetached(it);
|
||||
}
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check iterators on an empty q
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Iterator it = q.iterator();
|
||||
check(itrs(q) == null);
|
||||
if (rnd.nextBoolean()) checkExhausted(it);
|
||||
if (rnd.nextBoolean()) checkDetached(it);
|
||||
checkRemoveThrowsISE(it);
|
||||
}
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check "interior" removal of iterator's last element
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Iterator it = q.iterator();
|
||||
its.add(it);
|
||||
for (int j = 0; j < i; j++)
|
||||
equal(j, it.next());
|
||||
equal(attachedIterators(q), its);
|
||||
}
|
||||
q.remove(capacity - 1);
|
||||
equal(attachedIterators(q), its);
|
||||
for (int i = 1; i < capacity - 1; i++) {
|
||||
q.remove(capacity - i - 1);
|
||||
Iterator it = its.get(capacity - i);
|
||||
checkDetached(it);
|
||||
equal(attachedIterators(q), its.subList(0, capacity - i));
|
||||
if (rnd.nextBoolean()) check(it.hasNext());
|
||||
equal(it.next(), capacity - i);
|
||||
checkExhausted(it);
|
||||
}
|
||||
equal(attachedIterators(q), its.subList(0, 2));
|
||||
q.remove(0);
|
||||
check(q.isEmpty());
|
||||
check(itrs(q) == null);
|
||||
Iterator it = its.get(0);
|
||||
equal(it.next(), 0);
|
||||
checkRemoveHasNoEffect(it, q);
|
||||
checkExhausted(it);
|
||||
checkDetached(it);
|
||||
checkRemoveHasNoEffect(its.get(1), q);
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check "interior" removal of alternating elements, straddling 2 cycles
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
// Move takeIndex to middle
|
||||
for (int i = 0; i < capacity/2; i++) {
|
||||
check(q.add(i));
|
||||
equal(q.poll(), i);
|
||||
}
|
||||
check(takeIndex(q) == capacity/2);
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Iterator it = q.iterator();
|
||||
its.add(it);
|
||||
for (int j = 0; j < i; j++)
|
||||
equal(j, it.next());
|
||||
equal(attachedIterators(q), its);
|
||||
}
|
||||
// Remove all even elements, in either direction using
|
||||
// q.remove(), or iterator.remove()
|
||||
switch (rnd.nextInt(3)) {
|
||||
case 0:
|
||||
for (int i = 0; i < capacity; i+=2) {
|
||||
check(q.remove(i));
|
||||
equal(attachedIterators(q), its);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (int i = capacity - 2; i >= 0; i-=2) {
|
||||
check(q.remove(i));
|
||||
equal(attachedIterators(q), its);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
Iterator it = q.iterator();
|
||||
while (it.hasNext()) {
|
||||
int i = (Integer) it.next();
|
||||
if ((i & 1) == 0)
|
||||
it.remove();
|
||||
}
|
||||
equal(attachedIterators(q), its);
|
||||
break;
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Iterator it = its.get(i);
|
||||
boolean even = ((i & 1) == 0);
|
||||
if (even) {
|
||||
if (rnd.nextBoolean()) check(it.hasNext());
|
||||
equal(i, it.next());
|
||||
for (int j = i+1; j < capacity; j += 2)
|
||||
equal(j, it.next());
|
||||
check(!isDetached(it));
|
||||
check(!it.hasNext());
|
||||
check(isDetached(it));
|
||||
} else { /* odd */
|
||||
if (rnd.nextBoolean()) check(it.hasNext());
|
||||
checkRemoveHasNoEffect(it, q);
|
||||
equal(i, it.next());
|
||||
for (int j = i+2; j < capacity; j += 2)
|
||||
equal(j, it.next());
|
||||
check(!isDetached(it));
|
||||
check(!it.hasNext());
|
||||
check(isDetached(it));
|
||||
}
|
||||
}
|
||||
equal(trackedIterators(q), Collections.emptyList());
|
||||
check(itrs(q) == null);
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check garbage collection of discarded iterators
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
its.add(q.iterator());
|
||||
equal(attachedIterators(q), its);
|
||||
}
|
||||
its = null;
|
||||
waitForFinalizersToRun();
|
||||
List<Iterator> trackedIterators = trackedIterators(q);
|
||||
equal(trackedIterators.size(), capacity);
|
||||
for (Iterator x : trackedIterators)
|
||||
check(x == null);
|
||||
Iterator it = q.iterator();
|
||||
equal(trackedIterators(q), Collections.singletonList(it));
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check garbage collection of discarded iterators,
|
||||
// with a randomly retained subset.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
List<Iterator> retained = new ArrayList<>();
|
||||
final int size = 1 + rnd.nextInt(capacity);
|
||||
for (int i = 0; i < size; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Iterator it = q.iterator();
|
||||
its.add(it);
|
||||
equal(attachedIterators(q), its);
|
||||
}
|
||||
// Leave sufficient gaps in retained
|
||||
for (int i = 0; i < size; i+= 2+rnd.nextInt(3))
|
||||
retained.add(its.get(i));
|
||||
its = null;
|
||||
waitForFinalizersToRun();
|
||||
List<Iterator> trackedIterators = trackedIterators(q);
|
||||
equal(trackedIterators.size(), size);
|
||||
for (Iterator it : trackedIterators)
|
||||
check((it == null) ^ retained.contains(it));
|
||||
Iterator it = q.iterator(); // trigger another sweep
|
||||
retained.add(it);
|
||||
equal(trackedIterators(q), retained);
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check incremental sweeping of discarded iterators.
|
||||
// Excessively white box?!
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
final int SHORT_SWEEP_PROBES = 4;
|
||||
final int LONG_SWEEP_PROBES = 16;
|
||||
final int PROBE_HOP = LONG_SWEEP_PROBES + 6 * SHORT_SWEEP_PROBES;
|
||||
final int PROBE_HOP_COUNT = 10;
|
||||
// Expect around 8 sweeps per PROBE_HOP
|
||||
final int SWEEPS_PER_PROBE_HOP = 8;
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < PROBE_HOP_COUNT * PROBE_HOP; i++) {
|
||||
its.add(q.iterator());
|
||||
equal(attachedIterators(q), its);
|
||||
}
|
||||
// make some garbage, separated by PROBE_HOP
|
||||
for (int i = 0; i < its.size(); i += PROBE_HOP)
|
||||
its.set(i, null);
|
||||
waitForFinalizersToRun();
|
||||
int retries;
|
||||
for (retries = 0;
|
||||
trackedIterators(q).contains(null) && retries < 1000;
|
||||
retries++)
|
||||
// one round of sweeping
|
||||
its.add(q.iterator());
|
||||
check(retries >= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP - 2));
|
||||
check(retries <= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP + 2));
|
||||
Iterator itsit = its.iterator();
|
||||
while (itsit.hasNext())
|
||||
if (itsit.next() == null)
|
||||
itsit.remove();
|
||||
equal(trackedIterators(q), its);
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check safety of iterator.remove while in detached mode.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity/2; i++) {
|
||||
q.add(i);
|
||||
q.remove();
|
||||
}
|
||||
check(takeIndex(q) == capacity/2);
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Iterator it = q.iterator();
|
||||
its.add(it);
|
||||
for (int j = 0; j < i; j++)
|
||||
equal(j, it.next());
|
||||
equal(attachedIterators(q), its);
|
||||
}
|
||||
for (int i = capacity - 1; i >= 0; i--) {
|
||||
Iterator it = its.get(i);
|
||||
equal(i, it.next()); // last element
|
||||
check(!isDetached(it));
|
||||
check(!it.hasNext()); // first hasNext failure
|
||||
check(isDetached(it));
|
||||
int size = q.size();
|
||||
check(q.contains(i));
|
||||
switch (rnd.nextInt(3)) {
|
||||
case 0:
|
||||
it.remove();
|
||||
check(!q.contains(i));
|
||||
equal(q.size(), size - 1);
|
||||
break;
|
||||
case 1:
|
||||
// replace i with impostor
|
||||
if (q.remainingCapacity() == 0) {
|
||||
check(q.remove(i));
|
||||
check(q.add(-1));
|
||||
} else {
|
||||
check(q.add(-1));
|
||||
check(q.remove(i));
|
||||
}
|
||||
it.remove(); // should have no effect
|
||||
equal(size, q.size());
|
||||
check(q.contains(-1));
|
||||
check(q.remove(-1));
|
||||
break;
|
||||
case 2:
|
||||
// replace i with true impostor
|
||||
if (i != 0) {
|
||||
check(q.remove(i));
|
||||
check(q.add(i));
|
||||
}
|
||||
it.remove();
|
||||
check(!q.contains(i));
|
||||
equal(q.size(), size - 1);
|
||||
break;
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
checkRemoveThrowsISE(it);
|
||||
check(isDetached(it));
|
||||
check(!trackedIterators(q).contains(it));
|
||||
}
|
||||
check(q.isEmpty());
|
||||
check(itrs(q) == null);
|
||||
for (Iterator it : its)
|
||||
checkExhausted(it);
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check dequeues bypassing iterators' current positions.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
Queue<Iterator> its0 = new ArrayDeque<>();
|
||||
Queue<Iterator> itsMid = new ArrayDeque<>();
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < 2 * capacity + 1; i++) {
|
||||
Iterator it = q.iterator();
|
||||
its.add(it);
|
||||
its0.add(it);
|
||||
}
|
||||
for (int i = 0; i < 2 * capacity + 1; i++) {
|
||||
Iterator it = q.iterator();
|
||||
for (int j = 0; j < capacity/2; j++)
|
||||
equal(j, it.next());
|
||||
its.add(it);
|
||||
itsMid.add(it);
|
||||
}
|
||||
for (int i = capacity; i < 3 * capacity; i++) {
|
||||
Iterator it;
|
||||
|
||||
it = its0.remove();
|
||||
checkRemoveThrowsISE(it);
|
||||
if (rnd.nextBoolean()) check(it.hasNext());
|
||||
equal(0, it.next());
|
||||
int victim = i - capacity;
|
||||
for (int j = victim + (victim == 0 ? 1 : 0); j < i; j++) {
|
||||
if (rnd.nextBoolean()) check(it.hasNext());
|
||||
equal(j, it.next());
|
||||
}
|
||||
checkExhausted(it);
|
||||
|
||||
it = itsMid.remove();
|
||||
if (victim >= capacity/2)
|
||||
checkRemoveHasNoEffect(it, q);
|
||||
equal(capacity/2, it.next());
|
||||
if (victim > capacity/2)
|
||||
checkRemoveHasNoEffect(it, q);
|
||||
for (int j = Math.max(victim, capacity/2 + 1); j < i; j++) {
|
||||
if (rnd.nextBoolean()) check(it.hasNext());
|
||||
equal(j, it.next());
|
||||
}
|
||||
checkExhausted(it);
|
||||
|
||||
if (rnd.nextBoolean()) {
|
||||
equal(victim, q.remove());
|
||||
} else {
|
||||
ArrayList list = new ArrayList(1);
|
||||
q.drainTo(list, 1);
|
||||
equal(list.size(), 1);
|
||||
equal(victim, list.get(0));
|
||||
}
|
||||
check(q.add(i));
|
||||
}
|
||||
// takeIndex has wrapped twice.
|
||||
Iterator it0 = its0.remove();
|
||||
Iterator itMid = itsMid.remove();
|
||||
check(isDetached(it0));
|
||||
check(isDetached(itMid));
|
||||
if (rnd.nextBoolean()) check(it0.hasNext());
|
||||
if (rnd.nextBoolean()) check(itMid.hasNext());
|
||||
checkRemoveThrowsISE(it0);
|
||||
checkRemoveHasNoEffect(itMid, q);
|
||||
if (rnd.nextBoolean()) equal(0, it0.next());
|
||||
if (rnd.nextBoolean()) equal(capacity/2, itMid.next());
|
||||
check(isDetached(it0));
|
||||
check(isDetached(itMid));
|
||||
equal(capacity, q.size());
|
||||
equal(0, q.remainingCapacity());
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check collective sanity of iteration, toArray() and toString()
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
checkIterationSanity(q);
|
||||
equal(capacity, q.size() + q.remainingCapacity());
|
||||
q.add(i);
|
||||
}
|
||||
for (int i = 0; i < (capacity + (capacity >> 1)); i++) {
|
||||
checkIterationSanity(q);
|
||||
equal(capacity, q.size() + q.remainingCapacity());
|
||||
equal(i, q.peek());
|
||||
equal(i, q.poll());
|
||||
checkIterationSanity(q);
|
||||
equal(capacity, q.size() + q.remainingCapacity());
|
||||
q.add(capacity + i);
|
||||
}
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
checkIterationSanity(q);
|
||||
equal(capacity, q.size() + q.remainingCapacity());
|
||||
int expected = i + capacity + (capacity >> 1);
|
||||
equal(expected, q.peek());
|
||||
equal(expected, q.poll());
|
||||
}
|
||||
checkIterationSanity(q);
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
volatile int passed = 0, failed = 0;
|
||||
void pass() {passed++;}
|
||||
void fail() {failed++; Thread.dumpStack();}
|
||||
void fail(String msg) {System.err.println(msg); fail();}
|
||||
void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
void check(boolean cond) {if (cond) pass(); else fail();}
|
||||
void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
public static void main(String[] args) throws Throwable {
|
||||
new IteratorConsistency().instanceMain(args);}
|
||||
public void instanceMain(String[] args) throws Throwable {
|
||||
try {test(args);} catch (Throwable t) {unexpected(t);}
|
||||
System.err.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
}
|
759
jdk/test/java/util/concurrent/ArrayBlockingQueue/WhiteBox.java
Normal file
759
jdk/test/java/util/concurrent/ArrayBlockingQueue/WhiteBox.java
Normal file
@ -0,0 +1,759 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Written by Martin Buchholz with assistance from members of JCP
|
||||
* JSR-166 Expert Group and released to the public domain, as
|
||||
* explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @modules java.base/java.util.concurrent:open
|
||||
* @run testng WhiteBox
|
||||
* @summary White box tests of implementation details
|
||||
*/
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
@Test
|
||||
public class WhiteBox {
|
||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle ITRS, ITEMS, TAKEINDEX, PUTINDEX, COUNT, HEAD, NEXT, PREVTAKEINDEX;
|
||||
|
||||
WhiteBox() throws ReflectiveOperationException {
|
||||
Class<?> qClass = ArrayBlockingQueue.class;
|
||||
Class<?> itrClass = Class.forName(qClass.getName() + "$Itr");
|
||||
Class<?> itrsClass = Class.forName(qClass.getName() + "$Itrs");
|
||||
Class<?> nodeClass = Class.forName(itrsClass.getName() + "$Node");
|
||||
ITRS = findVarHandle(qClass, "itrs", itrsClass);
|
||||
ITEMS = findVarHandle(qClass, "items", Object[].class);
|
||||
TAKEINDEX = findVarHandle(qClass, "takeIndex", int.class);
|
||||
PUTINDEX = findVarHandle(qClass, "putIndex", int.class);
|
||||
COUNT = findVarHandle(qClass, "count", int.class);
|
||||
HEAD = findVarHandle(itrsClass, "head", nodeClass);
|
||||
NEXT = findVarHandle(nodeClass, "next", nodeClass);
|
||||
PREVTAKEINDEX = findVarHandle(itrClass, "prevTakeIndex", int.class);
|
||||
}
|
||||
|
||||
VarHandle findVarHandle(Class<?> recv, String name, Class<?> type)
|
||||
throws ReflectiveOperationException {
|
||||
return MethodHandles.privateLookupIn(recv, lookup)
|
||||
.findVarHandle(recv, name, type);
|
||||
}
|
||||
|
||||
Object itrs(ArrayBlockingQueue q) { return ITRS.get(q); }
|
||||
Object[] items(ArrayBlockingQueue q) { return (Object[]) ITEMS.get(q); }
|
||||
int takeIndex(ArrayBlockingQueue q) { return (int) TAKEINDEX.get(q); }
|
||||
int putIndex(ArrayBlockingQueue q) { return (int) PUTINDEX.get(q); }
|
||||
int count(ArrayBlockingQueue q) { return (int) COUNT.get(q); }
|
||||
Object head(Object itrs) { return HEAD.get(itrs); }
|
||||
Object next(Object node) { return NEXT.get(node); }
|
||||
int prevTakeIndex(Iterator itr) { return (int) PREVTAKEINDEX.get(itr); }
|
||||
|
||||
boolean isDetached(Iterator it) {
|
||||
return prevTakeIndex(it) < 0;
|
||||
}
|
||||
|
||||
void assertIteratorExhausted(Iterator it) {
|
||||
if (rnd.nextBoolean()) {
|
||||
assertTrue(!it.hasNext());
|
||||
assertTrue(isDetached(it));
|
||||
}
|
||||
if (rnd.nextBoolean()) {
|
||||
it.forEachRemaining(e -> { throw new AssertionError(); });
|
||||
assertTrue(isDetached(it));
|
||||
}
|
||||
if (rnd.nextBoolean())
|
||||
try { it.next(); fail("should throw"); }
|
||||
catch (NoSuchElementException success) {}
|
||||
}
|
||||
|
||||
List<Iterator> trackedIterators(ArrayBlockingQueue q) {
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
Object itrs = itrs(q);
|
||||
if (itrs != null) {
|
||||
for (Object p = head(itrs); p != null; p = next(p))
|
||||
its.add(((WeakReference<Iterator>)(p)).get());
|
||||
Collections.reverse(its);
|
||||
}
|
||||
return its;
|
||||
}
|
||||
|
||||
List<Iterator> attachedIterators(ArrayBlockingQueue q) {
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
Object itrs = itrs(q);
|
||||
if (itrs != null) {
|
||||
for (Object p = head(itrs); p != null; p = next(p)) {
|
||||
Iterator it = ((WeakReference<Iterator>)(p)).get();
|
||||
if (it != null && !isDetached(it))
|
||||
its.add(it);
|
||||
}
|
||||
Collections.reverse(its);
|
||||
}
|
||||
return its;
|
||||
}
|
||||
|
||||
void assertRemoveThrowsISE(Iterator it) {
|
||||
if (rnd.nextBoolean())
|
||||
try { it.remove(); fail("should throw"); }
|
||||
catch (IllegalStateException success) {}
|
||||
}
|
||||
|
||||
void assertRemoveHasNoEffect(Iterator it, Collection c) {
|
||||
if (rnd.nextBoolean()) {
|
||||
int size = c.size();
|
||||
it.remove(); // no effect
|
||||
assertEquals(c.size(), size);
|
||||
assertRemoveThrowsISE(it);
|
||||
}
|
||||
}
|
||||
|
||||
void checkIterationSanity(Queue q) {
|
||||
if (rnd.nextBoolean())
|
||||
return;
|
||||
int size = q.size();
|
||||
Object[] a = q.toArray();
|
||||
Object[] b = new Object[size+2];
|
||||
Arrays.fill(b, Boolean.TRUE);
|
||||
Object[] c = q.toArray(b);
|
||||
assertEquals(a.length, size);
|
||||
assertSame(b, c);
|
||||
assertNull(b[size]);
|
||||
assertSame(b[size+1], Boolean.TRUE);
|
||||
assertEquals(q.toString(), Arrays.toString(a));
|
||||
Integer[] xx = null, yy = null;
|
||||
if (size > 0) {
|
||||
xx = new Integer[size - 1];
|
||||
Arrays.fill(xx, 42);
|
||||
yy = ((Queue<Integer>)q).toArray(xx);
|
||||
for (Integer zz : xx)
|
||||
assertEquals(42, (int) zz);
|
||||
}
|
||||
Iterator it = q.iterator();
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
Object x = it.next();
|
||||
assertSame(x, a[i]);
|
||||
assertSame(x, b[i]);
|
||||
if (xx != null) assertSame(x, yy[i]);
|
||||
}
|
||||
if (rnd.nextBoolean()) assertTrue(!it.hasNext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instead of having putIndex (and takeIndex) at the initial
|
||||
* default of 0, move them to a random location.
|
||||
*/
|
||||
void randomizePutIndex(ArrayBlockingQueue q) {
|
||||
assertTrue(q.isEmpty());
|
||||
int capacity = q.remainingCapacity();
|
||||
int n = rnd.nextInt(capacity + 1);
|
||||
int putIndex = putIndex(q);
|
||||
for (int i = n; i-->0; ) q.add(Boolean.TRUE);
|
||||
for (int i = n; i-->0; ) q.remove();
|
||||
assertEquals(putIndex(q), (putIndex + n) % items(q).length);
|
||||
}
|
||||
|
||||
/** No guarantees, but effective in practice. */
|
||||
static void forceFullGc() {
|
||||
CountDownLatch finalizeDone = new CountDownLatch(1);
|
||||
WeakReference<?> ref = new WeakReference<Object>(new Object() {
|
||||
protected void finalize() { finalizeDone.countDown(); }});
|
||||
try {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
System.gc();
|
||||
if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
|
||||
System.runFinalization(); // try to pick up stragglers
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException unexpected) {
|
||||
throw new AssertionError("unexpected InterruptedException");
|
||||
}
|
||||
throw new AssertionError("failed to do a \"full\" gc");
|
||||
}
|
||||
|
||||
static void gcAwait(BooleanSupplier s) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (s.getAsBoolean())
|
||||
return;
|
||||
forceFullGc();
|
||||
}
|
||||
throw new AssertionError("failed to satisfy condition");
|
||||
}
|
||||
|
||||
public void clear_willClearItrs() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(2, 10);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
assertTrue(q.add(i));
|
||||
assertNull(itrs(q));
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
its.add(q.iterator());
|
||||
assertEquals(trackedIterators(q), its);
|
||||
q.poll();
|
||||
q.add(capacity + i);
|
||||
}
|
||||
q.clear();
|
||||
assertNull(itrs(q));
|
||||
int j = 0;
|
||||
for (Iterator it : its) {
|
||||
assertTrue(isDetached(it));
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
if (rnd.nextBoolean()) {
|
||||
assertEquals(it.next(), j);
|
||||
assertIteratorExhausted(it);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
public void queueEmptyingWillClearItrs() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(2, 10);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
assertNull(itrs(q));
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
its.add(q.iterator());
|
||||
assertEquals(trackedIterators(q), its);
|
||||
q.poll();
|
||||
q.add(capacity+i);
|
||||
}
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.poll();
|
||||
assertNull(itrs(q));
|
||||
int j = 0;
|
||||
for (Iterator it : its) {
|
||||
assertTrue(isDetached(it));
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
if (rnd.nextBoolean()) {
|
||||
assertEquals(it.next(), j);
|
||||
assertIteratorExhausted(it);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
public void advancing2CyclesWillRemoveIterators() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(2, 10);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
assertNull(itrs(q));
|
||||
for (int i = capacity; i < 3 * capacity; i++) {
|
||||
its.add(q.iterator());
|
||||
assertEquals(trackedIterators(q), its);
|
||||
q.poll();
|
||||
q.add(i);
|
||||
}
|
||||
for (int i = 3 * capacity; i < 4 * capacity; i++) {
|
||||
assertEquals(trackedIterators(q), its.subList(capacity,2*capacity));
|
||||
q.poll();
|
||||
q.add(i);
|
||||
}
|
||||
assertNull(itrs(q));
|
||||
int j = 0;
|
||||
for (Iterator it : its) {
|
||||
assertTrue(isDetached(it));
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
if (rnd.nextBoolean()) {
|
||||
assertEquals(it.next(), j);
|
||||
assertIteratorExhausted(it);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interior removal of elements used by an iterator will cause it
|
||||
* to be untracked.
|
||||
*/
|
||||
public void interiorRemovalOfElementsUsedByIterator() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(10, 20);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
q.add(0);
|
||||
for (int i = 1; i < 2 * capacity; i++) {
|
||||
q.add(i);
|
||||
Integer[] elts = { -1, -2, -3 };
|
||||
for (Integer elt : elts) q.add(elt);
|
||||
assertEquals(q.remove(), i - 1);
|
||||
Iterator it = q.iterator();
|
||||
assertEquals(it.next(), i);
|
||||
assertEquals(it.next(), elts[0]);
|
||||
Collections.shuffle(Arrays.asList(elts));
|
||||
assertTrue(q.remove(elts[0]));
|
||||
assertTrue(q.remove(elts[1]));
|
||||
assertEquals(trackedIterators(q), Collections.singletonList(it));
|
||||
assertTrue(q.remove(elts[2]));
|
||||
assertNull(itrs(q));
|
||||
assertEquals(it.next(), -2);
|
||||
assertIteratorExhausted(it);
|
||||
assertTrue(isDetached(it));
|
||||
}
|
||||
}
|
||||
|
||||
public void iteratorsOnEmptyQueue() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(1, 10);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Iterator it = q.iterator();
|
||||
assertNull(itrs(q));
|
||||
assertIteratorExhausted(it);
|
||||
assertTrue(isDetached(it));
|
||||
assertRemoveThrowsISE(it);
|
||||
}
|
||||
}
|
||||
|
||||
public void interiorRemovalOfIteratorsLastElement() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(3, 10);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Iterator it = q.iterator();
|
||||
its.add(it);
|
||||
for (int j = 0; j < i; j++)
|
||||
assertEquals(j, it.next());
|
||||
assertEquals(attachedIterators(q), its);
|
||||
}
|
||||
q.remove(capacity - 1);
|
||||
assertEquals(attachedIterators(q), its);
|
||||
for (int i = 1; i < capacity - 1; i++) {
|
||||
q.remove(capacity - i - 1);
|
||||
Iterator it = its.get(capacity - i);
|
||||
assertTrue(isDetached(it));
|
||||
assertEquals(attachedIterators(q), its.subList(0, capacity - i));
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
assertEquals(it.next(), capacity - i);
|
||||
assertIteratorExhausted(it);
|
||||
}
|
||||
assertEquals(attachedIterators(q), its.subList(0, 2));
|
||||
q.remove(0);
|
||||
assertTrue(q.isEmpty());
|
||||
assertNull(itrs(q));
|
||||
Iterator it = its.get(0);
|
||||
assertEquals(it.next(), 0);
|
||||
assertRemoveHasNoEffect(it, q);
|
||||
assertIteratorExhausted(it);
|
||||
assertTrue(isDetached(it));
|
||||
assertRemoveHasNoEffect(its.get(1), q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks "interior" removal of alternating elements, straddling 2 cycles
|
||||
*/
|
||||
public void interiorRemovalOfAlternatingElements() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = 2 * rnd.nextInt(2, 10);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
// Move takeIndex to middle
|
||||
for (int i = 0; i < capacity/2; i++) {
|
||||
assertTrue(q.add(i));
|
||||
assertEquals(q.poll(), i);
|
||||
}
|
||||
assertEquals(takeIndex(q), capacity/2);
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Iterator it = q.iterator();
|
||||
its.add(it);
|
||||
for (int j = 0; j < i; j++)
|
||||
assertEquals(j, it.next());
|
||||
assertEquals(attachedIterators(q), its);
|
||||
}
|
||||
|
||||
// Remove all even elements, in either direction, using
|
||||
// q.remove(), or iterator.remove()
|
||||
switch (rnd.nextInt(3)) {
|
||||
case 0:
|
||||
for (int i = 0; i < capacity; i+=2) assertTrue(q.remove(i));
|
||||
break;
|
||||
case 1:
|
||||
for (int i = capacity - 2; i >= 0; i-=2) assertTrue(q.remove(i));
|
||||
break;
|
||||
case 2:
|
||||
Iterator it = q.iterator();
|
||||
while (it.hasNext()) {
|
||||
int i = (Integer) it.next();
|
||||
if ((i & 1) == 0)
|
||||
it.remove();
|
||||
}
|
||||
break;
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
assertEquals(attachedIterators(q), its);
|
||||
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Iterator it = its.get(i);
|
||||
boolean even = ((i & 1) == 0);
|
||||
if (even) {
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
assertEquals(i, it.next());
|
||||
for (int j = i+1; j < capacity; j += 2)
|
||||
assertEquals(j, it.next());
|
||||
assertTrue(!isDetached(it));
|
||||
assertTrue(!it.hasNext());
|
||||
assertTrue(isDetached(it));
|
||||
} else { /* odd */
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
assertRemoveHasNoEffect(it, q);
|
||||
assertEquals(i, it.next());
|
||||
for (int j = i+2; j < capacity; j += 2)
|
||||
assertEquals(j, it.next());
|
||||
assertTrue(!isDetached(it));
|
||||
assertTrue(!it.hasNext());
|
||||
assertTrue(isDetached(it));
|
||||
}
|
||||
}
|
||||
assertEquals(trackedIterators(q), Collections.emptyList());
|
||||
assertNull(itrs(q));
|
||||
}
|
||||
|
||||
public void garbageCollectionOfUnreachableIterators() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(1, 10);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++) q.add(i);
|
||||
for (int i = 0; i < capacity; i++) its.add(q.iterator());
|
||||
assertEquals(attachedIterators(q), its);
|
||||
its = null;
|
||||
gcAwait(() -> {
|
||||
List<Iterator> trackedIterators = trackedIterators(q);
|
||||
assertEquals(trackedIterators.size(), capacity);
|
||||
for (Iterator x : trackedIterators)
|
||||
if (x != null) return false;
|
||||
return true;
|
||||
});
|
||||
Iterator it = q.iterator(); //
|
||||
assertEquals(trackedIterators(q), Collections.singletonList(it));
|
||||
}
|
||||
|
||||
public void garbageCollectionOfUnreachableIteratorsWithRandomlyRetainedSubset() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(10, 20);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
List<Iterator> retained = new ArrayList<>();
|
||||
final int size = 1 + rnd.nextInt(capacity);
|
||||
for (int i = 0; i < size; i++) q.add(i);
|
||||
for (int i = 0; i < size; i++) its.add(q.iterator());
|
||||
assertEquals(attachedIterators(q), its);
|
||||
// Leave sufficient gaps in retained
|
||||
for (int i = 0; i < size; i+= 2+rnd.nextInt(3))
|
||||
retained.add(its.get(i));
|
||||
its = null;
|
||||
gcAwait(() -> {
|
||||
List<Iterator> trackedIterators = trackedIterators(q);
|
||||
assertEquals(trackedIterators.size(), size);
|
||||
for (Iterator it : trackedIterators)
|
||||
if ((it != null) ^ retained.contains(it)) return false;
|
||||
return true;
|
||||
});
|
||||
Iterator it = q.iterator(); // trigger another sweep
|
||||
retained.add(it);
|
||||
assertEquals(trackedIterators(q), retained);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks incremental sweeping of unreachable iterators.
|
||||
* Excessively white box?!
|
||||
*/
|
||||
public void incrementalSweepingOfUnreachableIterators() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(10, 20);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
final int SHORT_SWEEP_PROBES = 4;
|
||||
final int LONG_SWEEP_PROBES = 16;
|
||||
final int PROBE_HOP = LONG_SWEEP_PROBES + 6 * SHORT_SWEEP_PROBES;
|
||||
final int PROBE_HOP_COUNT = 10;
|
||||
// Expect around 8 sweeps per PROBE_HOP
|
||||
final int SWEEPS_PER_PROBE_HOP = 8;
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < PROBE_HOP_COUNT * PROBE_HOP; i++)
|
||||
its.add(q.iterator());
|
||||
assertEquals(attachedIterators(q), its);
|
||||
// make some garbage, separated by PROBE_HOP
|
||||
for (int i = 0; i < its.size(); i += PROBE_HOP)
|
||||
its.set(i, null);
|
||||
its.removeIf(it -> it == null);
|
||||
forceFullGc();
|
||||
int retries;
|
||||
for (retries = 0;
|
||||
trackedIterators(q).contains(null) && retries < 1000;
|
||||
retries++)
|
||||
// one round of sweeping
|
||||
its.add(q.iterator());
|
||||
assertTrue(retries >= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP - 2));
|
||||
assertTrue(retries <= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP + 2));
|
||||
assertEquals(trackedIterators(q), its);
|
||||
}
|
||||
|
||||
public void Iterator_remove_safetyWhileInDetachedMode() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(10, 20);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity/2; i++) {
|
||||
q.add(i);
|
||||
q.remove();
|
||||
}
|
||||
assertEquals(takeIndex(q), capacity/2);
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Iterator it = q.iterator();
|
||||
its.add(it);
|
||||
for (int j = 0; j < i; j++)
|
||||
assertEquals(j, it.next());
|
||||
}
|
||||
assertEquals(attachedIterators(q), its);
|
||||
for (int i = capacity - 1; i >= 0; i--) {
|
||||
Iterator it = its.get(i);
|
||||
assertEquals(i, it.next()); // last element
|
||||
assertTrue(!isDetached(it));
|
||||
assertTrue(!it.hasNext()); // first hasNext failure
|
||||
assertTrue(isDetached(it));
|
||||
int size = q.size();
|
||||
assertTrue(q.contains(i));
|
||||
switch (rnd.nextInt(3)) {
|
||||
case 0:
|
||||
it.remove();
|
||||
assertTrue(!q.contains(i));
|
||||
assertEquals(q.size(), size - 1);
|
||||
break;
|
||||
case 1:
|
||||
// replace i with impostor
|
||||
if (q.remainingCapacity() == 0) {
|
||||
assertTrue(q.remove(i));
|
||||
assertTrue(q.add(-1));
|
||||
} else {
|
||||
assertTrue(q.add(-1));
|
||||
assertTrue(q.remove(i));
|
||||
}
|
||||
it.remove(); // should have no effect
|
||||
assertEquals(size, q.size());
|
||||
assertTrue(q.contains(-1));
|
||||
assertTrue(q.remove(-1));
|
||||
break;
|
||||
case 2:
|
||||
// replace i with true impostor
|
||||
if (i != 0) {
|
||||
assertTrue(q.remove(i));
|
||||
assertTrue(q.add(i));
|
||||
}
|
||||
it.remove();
|
||||
assertTrue(!q.contains(i));
|
||||
assertEquals(q.size(), size - 1);
|
||||
break;
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
assertRemoveThrowsISE(it);
|
||||
assertTrue(isDetached(it));
|
||||
assertTrue(!trackedIterators(q).contains(it));
|
||||
}
|
||||
assertTrue(q.isEmpty());
|
||||
assertNull(itrs(q));
|
||||
for (Iterator it : its)
|
||||
assertIteratorExhausted(it);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks dequeues bypassing iterators' current positions.
|
||||
*/
|
||||
public void dequeuesBypassingIteratorCurrentPositions() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(10, 20);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
Queue<Iterator> its0 = new ArrayDeque<>();
|
||||
Queue<Iterator> itsMid = new ArrayDeque<>();
|
||||
List<Iterator> its = new ArrayList<>();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
q.add(i);
|
||||
for (int i = 0; i < 2 * capacity + 1; i++) {
|
||||
Iterator it = q.iterator();
|
||||
its.add(it);
|
||||
its0.add(it);
|
||||
}
|
||||
for (int i = 0; i < 2 * capacity + 1; i++) {
|
||||
Iterator it = q.iterator();
|
||||
for (int j = 0; j < capacity/2; j++)
|
||||
assertEquals(j, it.next());
|
||||
its.add(it);
|
||||
itsMid.add(it);
|
||||
}
|
||||
for (int i = capacity; i < 3 * capacity; i++) {
|
||||
Iterator it;
|
||||
|
||||
it = its0.remove();
|
||||
assertRemoveThrowsISE(it);
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
assertEquals(0, it.next());
|
||||
int victim = i - capacity;
|
||||
for (int j = victim + (victim == 0 ? 1 : 0); j < i; j++) {
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
assertEquals(j, it.next());
|
||||
}
|
||||
assertIteratorExhausted(it);
|
||||
|
||||
it = itsMid.remove();
|
||||
if (victim >= capacity/2)
|
||||
assertRemoveHasNoEffect(it, q);
|
||||
assertEquals(capacity/2, it.next());
|
||||
if (victim > capacity/2)
|
||||
assertRemoveHasNoEffect(it, q);
|
||||
for (int j = Math.max(victim, capacity/2 + 1); j < i; j++) {
|
||||
if (rnd.nextBoolean()) assertTrue(it.hasNext());
|
||||
assertEquals(j, it.next());
|
||||
}
|
||||
assertIteratorExhausted(it);
|
||||
|
||||
if (rnd.nextBoolean()) {
|
||||
assertEquals(victim, q.remove());
|
||||
} else {
|
||||
ArrayList list = new ArrayList(1);
|
||||
q.drainTo(list, 1);
|
||||
assertEquals(list.size(), 1);
|
||||
assertEquals(victim, list.get(0));
|
||||
}
|
||||
assertTrue(q.add(i));
|
||||
}
|
||||
// takeIndex has wrapped twice.
|
||||
Iterator it0 = its0.remove();
|
||||
Iterator itMid = itsMid.remove();
|
||||
assertTrue(isDetached(it0));
|
||||
assertTrue(isDetached(itMid));
|
||||
if (rnd.nextBoolean()) assertTrue(it0.hasNext());
|
||||
if (rnd.nextBoolean()) assertTrue(itMid.hasNext());
|
||||
assertRemoveThrowsISE(it0);
|
||||
assertRemoveHasNoEffect(itMid, q);
|
||||
if (rnd.nextBoolean()) assertEquals(0, it0.next());
|
||||
if (rnd.nextBoolean()) assertEquals(capacity/2, itMid.next());
|
||||
assertTrue(isDetached(it0));
|
||||
assertTrue(isDetached(itMid));
|
||||
assertEquals(capacity, q.size());
|
||||
assertEquals(0, q.remainingCapacity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks collective sanity of iteration, toArray() and toString().
|
||||
*/
|
||||
public void collectiveSanity() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(10, 20);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
checkIterationSanity(q);
|
||||
assertEquals(capacity, q.size() + q.remainingCapacity());
|
||||
q.add(i);
|
||||
}
|
||||
for (int i = 0; i < (capacity + (capacity >> 1)); i++) {
|
||||
checkIterationSanity(q);
|
||||
assertEquals(capacity, q.size() + q.remainingCapacity());
|
||||
assertEquals(i, q.peek());
|
||||
assertEquals(i, q.poll());
|
||||
checkIterationSanity(q);
|
||||
assertEquals(capacity, q.size() + q.remainingCapacity());
|
||||
q.add(capacity + i);
|
||||
}
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
checkIterationSanity(q);
|
||||
assertEquals(capacity, q.size() + q.remainingCapacity());
|
||||
int expected = i + capacity + (capacity >> 1);
|
||||
assertEquals(expected, q.peek());
|
||||
assertEquals(expected, q.poll());
|
||||
}
|
||||
checkIterationSanity(q);
|
||||
}
|
||||
|
||||
public void iteratorsDetachedWhenExhaustedAndLastRetRemoved() {
|
||||
boolean fair = rnd.nextBoolean();
|
||||
int capacity = rnd.nextInt(2, 10);
|
||||
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
|
||||
randomizePutIndex(q);
|
||||
int size = rnd.nextInt(1, capacity + 1);
|
||||
for (int i = 0; i < size; i++) q.add(i);
|
||||
Iterator it = q.iterator();
|
||||
for (int i = 0; i < size - 1; i++) assertEquals(i, it.next());
|
||||
assertEquals(trackedIterators(q), Collections.singletonList(it));
|
||||
assertFalse(isDetached(it));
|
||||
switch (rnd.nextInt(2)) {
|
||||
case 0: assertTrue(q.remove(size - 1)); break;
|
||||
case 1: assertTrue(q.removeIf(e -> e.equals(size - 1))); break;
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
assertEquals(size - 1, it.next()); // should trigger detach
|
||||
assertNull(itrs(q));
|
||||
assertTrue(isDetached(it));
|
||||
assertRemoveHasNoEffect(it, q);
|
||||
}
|
||||
}
|
@ -34,12 +34,12 @@
|
||||
/*
|
||||
* @test
|
||||
* @summary Ensure that waiting pool threads don't retain refs to tasks.
|
||||
* @library /lib/testlibrary/
|
||||
*/
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
@ -47,10 +47,8 @@ import java.util.concurrent.RunnableScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import jdk.testlibrary.Utils;
|
||||
|
||||
public class GCRetention {
|
||||
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
|
||||
|
||||
/**
|
||||
* A custom thread pool with a custom RunnableScheduledFuture, for the
|
||||
@ -80,53 +78,48 @@ public class GCRetention {
|
||||
}
|
||||
}
|
||||
|
||||
int countRefsCleared(WeakReference<?>[] refs) {
|
||||
int count = 0;
|
||||
for (WeakReference<?> ref : refs)
|
||||
if (ref.get() == null)
|
||||
count++;
|
||||
return count;
|
||||
void removeAll(ReferenceQueue<?> q, int n) throws InterruptedException {
|
||||
for (int j = n; j--> 0; ) {
|
||||
if (q.poll() == null) {
|
||||
for (;;) {
|
||||
System.gc();
|
||||
if (q.remove(1000) != null)
|
||||
break;
|
||||
System.out.printf(
|
||||
"%d/%d unqueued references remaining%n", j, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
check(q.poll() == null);
|
||||
}
|
||||
|
||||
void test(String[] args) throws Throwable {
|
||||
CustomPool pool = new CustomPool(10);
|
||||
final CustomPool pool = new CustomPool(10);
|
||||
final int size = 100;
|
||||
WeakReference<?>[] refs = new WeakReference<?>[size];
|
||||
Future<?>[] futures = new Future<?>[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final Object x = new Object();
|
||||
refs[i] = new WeakReference<Object>(x);
|
||||
// Create a Runnable with a strong ref to x.
|
||||
Runnable r = new Runnable() {
|
||||
public void run() { System.out.println(x); }
|
||||
};
|
||||
// Schedule a custom task with a strong reference to r.
|
||||
// Later tasks have earlier expiration, to ensure multiple
|
||||
// residents of queue head.
|
||||
futures[i] = pool.schedule(r, size*2-i, TimeUnit.MINUTES);
|
||||
}
|
||||
Thread.sleep(10);
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (futures[i] != null) {
|
||||
futures[i].cancel(false);
|
||||
futures[i] = null;
|
||||
}
|
||||
final ReferenceQueue<Object> q = new ReferenceQueue<>();
|
||||
final List<WeakReference<?>> refs = new ArrayList<>(size);
|
||||
final List<Future<?>> futures = new ArrayList<>(size);
|
||||
|
||||
// Schedule custom tasks with strong references.
|
||||
class Task implements Runnable {
|
||||
final Object x;
|
||||
Task() { refs.add(new WeakReference<>(x = new Object(), q)); }
|
||||
public void run() { System.out.println(x); }
|
||||
}
|
||||
// Give tasks added later earlier expiration, to ensure
|
||||
// multiple residents of queue head.
|
||||
for (int i = size; i--> 0; )
|
||||
futures.add(pool.schedule(new Task(), i + 1, TimeUnit.MINUTES));
|
||||
futures.forEach(future -> future.cancel(false));
|
||||
futures.clear();
|
||||
|
||||
pool.purge();
|
||||
int cleared = 0;
|
||||
for (int i = 0;
|
||||
i < 10 && (cleared = countRefsCleared(refs)) < size;
|
||||
i++) {
|
||||
System.gc();
|
||||
System.runFinalization();
|
||||
Thread.sleep(10);
|
||||
}
|
||||
removeAll(q, size);
|
||||
for (WeakReference<?> ref : refs) check(ref.get() == null);
|
||||
|
||||
pool.shutdown();
|
||||
pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS);
|
||||
if (cleared < size)
|
||||
throw new Error(String.format
|
||||
("references to %d/%d tasks retained (\"leaked\")",
|
||||
size - cleared, size));
|
||||
// rely on test harness to handle timeout
|
||||
pool.awaitTermination(1L, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
|
@ -1326,20 +1326,60 @@ public class JSR166TestCase extends TestCase {
|
||||
startTime = System.nanoTime();
|
||||
else if (millisElapsedSince(startTime) > timeoutMillis) {
|
||||
threadAssertTrue(thread.isAlive());
|
||||
return;
|
||||
fail("timed out waiting for thread to enter wait state");
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits up to LONG_DELAY_MS for the given thread to enter a wait
|
||||
* state: BLOCKED, WAITING, or TIMED_WAITING.
|
||||
* Spin-waits up to the specified number of milliseconds for the given
|
||||
* thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING,
|
||||
* and additionally satisfy the given condition.
|
||||
*/
|
||||
void waitForThreadToEnterWaitState(
|
||||
Thread thread, long timeoutMillis, Callable<Boolean> waitingForGodot) {
|
||||
long startTime = 0L;
|
||||
for (;;) {
|
||||
Thread.State s = thread.getState();
|
||||
if (s == Thread.State.BLOCKED ||
|
||||
s == Thread.State.WAITING ||
|
||||
s == Thread.State.TIMED_WAITING) {
|
||||
try {
|
||||
if (waitingForGodot.call())
|
||||
return;
|
||||
} catch (Throwable fail) { threadUnexpectedException(fail); }
|
||||
}
|
||||
else if (s == Thread.State.TERMINATED)
|
||||
fail("Unexpected thread termination");
|
||||
else if (startTime == 0L)
|
||||
startTime = System.nanoTime();
|
||||
else if (millisElapsedSince(startTime) > timeoutMillis) {
|
||||
threadAssertTrue(thread.isAlive());
|
||||
fail("timed out waiting for thread to enter wait state");
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spin-waits up to LONG_DELAY_MS milliseconds for the given thread to
|
||||
* enter a wait state: BLOCKED, WAITING, or TIMED_WAITING.
|
||||
*/
|
||||
void waitForThreadToEnterWaitState(Thread thread) {
|
||||
waitForThreadToEnterWaitState(thread, LONG_DELAY_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spin-waits up to LONG_DELAY_MS milliseconds for the given thread to
|
||||
* enter a wait state: BLOCKED, WAITING, or TIMED_WAITING,
|
||||
* and additionally satisfy the given condition.
|
||||
*/
|
||||
void waitForThreadToEnterWaitState(
|
||||
Thread thread, Callable<Boolean> waitingForGodot) {
|
||||
waitForThreadToEnterWaitState(thread, LONG_DELAY_MS, waitingForGodot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of milliseconds since time given by
|
||||
* startNanoTime, which must have been previously returned from a
|
||||
|
@ -42,6 +42,7 @@ import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@ -766,9 +767,11 @@ public class LinkedTransferQueueTest extends JSR166TestCase {
|
||||
}});
|
||||
|
||||
threadStarted.await();
|
||||
waitForThreadToEnterWaitState(t);
|
||||
assertEquals(1, q.getWaitingConsumerCount());
|
||||
assertTrue(q.hasWaitingConsumer());
|
||||
Callable<Boolean> oneConsumer
|
||||
= new Callable<Boolean>() { public Boolean call() {
|
||||
return q.hasWaitingConsumer()
|
||||
&& q.getWaitingConsumerCount() == 1; }};
|
||||
waitForThreadToEnterWaitState(t, oneConsumer);
|
||||
|
||||
assertTrue(q.offer(one));
|
||||
assertEquals(0, q.getWaitingConsumerCount());
|
||||
@ -790,7 +793,7 @@ public class LinkedTransferQueueTest extends JSR166TestCase {
|
||||
|
||||
/**
|
||||
* transfer waits until a poll occurs. The transfered element
|
||||
* is returned by this associated poll.
|
||||
* is returned by the associated poll.
|
||||
*/
|
||||
public void testTransfer2() throws InterruptedException {
|
||||
final LinkedTransferQueue<Integer> q = new LinkedTransferQueue<>();
|
||||
@ -804,8 +807,11 @@ public class LinkedTransferQueueTest extends JSR166TestCase {
|
||||
}});
|
||||
|
||||
threadStarted.await();
|
||||
waitForThreadToEnterWaitState(t);
|
||||
assertEquals(1, q.size());
|
||||
Callable<Boolean> oneElement
|
||||
= new Callable<Boolean>() { public Boolean call() {
|
||||
return !q.isEmpty() && q.size() == 1; }};
|
||||
waitForThreadToEnterWaitState(t, oneElement);
|
||||
|
||||
assertSame(five, q.poll());
|
||||
checkEmpty(q);
|
||||
awaitTermination(t);
|
||||
@ -868,7 +874,7 @@ public class LinkedTransferQueueTest extends JSR166TestCase {
|
||||
|
||||
/**
|
||||
* transfer waits until a take occurs. The transfered element
|
||||
* is returned by this associated take.
|
||||
* is returned by the associated take.
|
||||
*/
|
||||
public void testTransfer5() throws InterruptedException {
|
||||
final LinkedTransferQueue<Integer> q = new LinkedTransferQueue<>();
|
||||
|
@ -550,7 +550,7 @@ public class PhaserTest extends JSR166TestCase {
|
||||
}});
|
||||
|
||||
await(pleaseArrive);
|
||||
waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
|
||||
waitForThreadToEnterWaitState(t);
|
||||
assertEquals(0, phaser.arrive());
|
||||
awaitTermination(t);
|
||||
|
||||
@ -578,7 +578,7 @@ public class PhaserTest extends JSR166TestCase {
|
||||
}});
|
||||
|
||||
await(pleaseArrive);
|
||||
waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
|
||||
waitForThreadToEnterWaitState(t);
|
||||
t.interrupt();
|
||||
assertEquals(0, phaser.arrive());
|
||||
awaitTermination(t);
|
||||
@ -594,20 +594,20 @@ public class PhaserTest extends JSR166TestCase {
|
||||
public void testArriveAndAwaitAdvanceAfterInterrupt() {
|
||||
final Phaser phaser = new Phaser();
|
||||
assertEquals(0, phaser.register());
|
||||
final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
|
||||
final CountDownLatch pleaseArrive = new CountDownLatch(1);
|
||||
|
||||
Thread t = newStartedThread(new CheckedRunnable() {
|
||||
public void realRun() {
|
||||
Thread.currentThread().interrupt();
|
||||
assertEquals(0, phaser.register());
|
||||
pleaseInterrupt.countDown();
|
||||
pleaseArrive.countDown();
|
||||
assertTrue(Thread.currentThread().isInterrupted());
|
||||
assertEquals(1, phaser.arriveAndAwaitAdvance());
|
||||
assertTrue(Thread.currentThread().isInterrupted());
|
||||
assertTrue(Thread.interrupted());
|
||||
}});
|
||||
|
||||
await(pleaseInterrupt);
|
||||
waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
|
||||
await(pleaseArrive);
|
||||
waitForThreadToEnterWaitState(t);
|
||||
Thread.currentThread().interrupt();
|
||||
assertEquals(1, phaser.arriveAndAwaitAdvance());
|
||||
assertTrue(Thread.interrupted());
|
||||
@ -628,11 +628,11 @@ public class PhaserTest extends JSR166TestCase {
|
||||
assertFalse(Thread.currentThread().isInterrupted());
|
||||
pleaseInterrupt.countDown();
|
||||
assertEquals(1, phaser.arriveAndAwaitAdvance());
|
||||
assertTrue(Thread.currentThread().isInterrupted());
|
||||
assertTrue(Thread.interrupted());
|
||||
}});
|
||||
|
||||
await(pleaseInterrupt);
|
||||
waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
|
||||
waitForThreadToEnterWaitState(t);
|
||||
t.interrupt();
|
||||
Thread.currentThread().interrupt();
|
||||
assertEquals(1, phaser.arriveAndAwaitAdvance());
|
||||
@ -807,7 +807,7 @@ public class PhaserTest extends JSR166TestCase {
|
||||
assertEquals(THREADS, phaser.getArrivedParties());
|
||||
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
|
||||
for (Thread thread : threads)
|
||||
waitForThreadToEnterWaitState(thread, SHORT_DELAY_MS);
|
||||
waitForThreadToEnterWaitState(thread);
|
||||
for (Thread thread : threads)
|
||||
assertTrue(thread.isAlive());
|
||||
assertState(phaser, 0, THREADS + 1, 1);
|
||||
|
@ -299,7 +299,6 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
* interruptible operations throw InterruptedException when pre-interrupted
|
||||
*/
|
||||
public void testInterruptibleOperationsThrowInterruptedExceptionWhenPreInterrupted() {
|
||||
final CountDownLatch running = new CountDownLatch(1);
|
||||
final StampedLock lock = new StampedLock();
|
||||
|
||||
Action[] interruptibleLockActions = {
|
||||
@ -364,7 +363,6 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
* interruptible operations throw InterruptedException when write locked and interrupted
|
||||
*/
|
||||
public void testInterruptibleOperationsThrowInterruptedExceptionWriteLockedInterrupted() {
|
||||
final CountDownLatch running = new CountDownLatch(1);
|
||||
final StampedLock lock = new StampedLock();
|
||||
long s = lock.writeLock();
|
||||
|
||||
@ -387,7 +385,6 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
* interruptible operations throw InterruptedException when read locked and interrupted
|
||||
*/
|
||||
public void testInterruptibleOperationsThrowInterruptedExceptionReadLockedInterrupted() {
|
||||
final CountDownLatch running = new CountDownLatch(1);
|
||||
final StampedLock lock = new StampedLock();
|
||||
long s = lock.readLock();
|
||||
|
||||
@ -506,29 +503,32 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* A writelock succeeds only after a reading thread unlocks
|
||||
* writeLock() succeeds only after a reading thread unlocks
|
||||
*/
|
||||
public void testWriteAfterReadLock() throws InterruptedException {
|
||||
final CountDownLatch running = new CountDownLatch(1);
|
||||
final CountDownLatch aboutToLock = new CountDownLatch(1);
|
||||
final StampedLock lock = new StampedLock();
|
||||
long rs = lock.readLock();
|
||||
Thread t = newStartedThread(new CheckedRunnable() {
|
||||
public void realRun() {
|
||||
running.countDown();
|
||||
aboutToLock.countDown();
|
||||
long s = lock.writeLock();
|
||||
assertTrue(lock.isWriteLocked());
|
||||
assertFalse(lock.isReadLocked());
|
||||
lock.unlockWrite(s);
|
||||
}});
|
||||
|
||||
running.await();
|
||||
waitForThreadToEnterWaitState(t, MEDIUM_DELAY_MS);
|
||||
aboutToLock.await();
|
||||
waitForThreadToEnterWaitState(t);
|
||||
assertFalse(lock.isWriteLocked());
|
||||
assertTrue(lock.isReadLocked());
|
||||
lock.unlockRead(rs);
|
||||
awaitTermination(t);
|
||||
assertFalse(lock.isWriteLocked());
|
||||
assertUnlocked(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* A writelock succeeds only after reading threads unlock
|
||||
* writeLock() succeeds only after reading threads unlock
|
||||
*/
|
||||
public void testWriteAfterMultipleReadLocks() {
|
||||
final StampedLock lock = new StampedLock();
|
||||
@ -551,35 +551,36 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
assertFalse(lock.isWriteLocked());
|
||||
lock.unlockRead(s);
|
||||
awaitTermination(t2);
|
||||
assertFalse(lock.isWriteLocked());
|
||||
assertUnlocked(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Readlocks succeed only after a writing thread unlocks
|
||||
* readLock() succeed only after a writing thread unlocks
|
||||
*/
|
||||
public void testReadAfterWriteLock() {
|
||||
final StampedLock lock = new StampedLock();
|
||||
final CountDownLatch threadsStarted = new CountDownLatch(2);
|
||||
final long s = lock.writeLock();
|
||||
Thread t1 = newStartedThread(new CheckedRunnable() {
|
||||
final Runnable acquireReleaseReadLock = new CheckedRunnable() {
|
||||
public void realRun() {
|
||||
threadsStarted.countDown();
|
||||
long rs = lock.readLock();
|
||||
assertTrue(lock.isReadLocked());
|
||||
assertFalse(lock.isWriteLocked());
|
||||
lock.unlockRead(rs);
|
||||
}});
|
||||
Thread t2 = newStartedThread(new CheckedRunnable() {
|
||||
public void realRun() {
|
||||
threadsStarted.countDown();
|
||||
long rs = lock.readLock();
|
||||
lock.unlockRead(rs);
|
||||
}});
|
||||
}};
|
||||
Thread t1 = newStartedThread(acquireReleaseReadLock);
|
||||
Thread t2 = newStartedThread(acquireReleaseReadLock);
|
||||
|
||||
await(threadsStarted);
|
||||
waitForThreadToEnterWaitState(t1, MEDIUM_DELAY_MS);
|
||||
waitForThreadToEnterWaitState(t2, MEDIUM_DELAY_MS);
|
||||
waitForThreadToEnterWaitState(t1);
|
||||
waitForThreadToEnterWaitState(t2);
|
||||
assertTrue(lock.isWriteLocked());
|
||||
assertFalse(lock.isReadLocked());
|
||||
releaseWriteLock(lock, s);
|
||||
awaitTermination(t1);
|
||||
awaitTermination(t2);
|
||||
assertUnlocked(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -765,22 +766,24 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
*/
|
||||
public void testValidateOptimisticWriteLocked2()
|
||||
throws InterruptedException {
|
||||
final CountDownLatch running = new CountDownLatch(1);
|
||||
final CountDownLatch locked = new CountDownLatch(1);
|
||||
final StampedLock lock = new StampedLock();
|
||||
final long p = assertValid(lock, lock.tryOptimisticRead());
|
||||
|
||||
Thread t = newStartedThread(new CheckedInterruptedRunnable() {
|
||||
public void realRun() throws InterruptedException {
|
||||
lock.writeLockInterruptibly();
|
||||
running.countDown();
|
||||
locked.countDown();
|
||||
lock.writeLockInterruptibly();
|
||||
}});
|
||||
|
||||
running.await();
|
||||
locked.await();
|
||||
assertFalse(lock.validate(p));
|
||||
assertEquals(0L, lock.tryOptimisticRead());
|
||||
waitForThreadToEnterWaitState(t);
|
||||
t.interrupt();
|
||||
awaitTermination(t);
|
||||
assertTrue(lock.isWriteLocked());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, 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
|
||||
@ -32,6 +32,7 @@ import jdk.internal.misc.SharedSecrets;
|
||||
* @summary Test JavaLangAccess.newUnsafeString
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @compile -XDignore.symbol.file NewUnsafeString.java
|
||||
* @run main NewUnsafeString
|
||||
*/
|
||||
public class NewUnsafeString {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, 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,8 +24,9 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 8050374
|
||||
* @compile ../../../java/security/SignedObject/Chain.java
|
||||
* @summary Verify a chain of signed objects
|
||||
* @compile ../../../java/security/SignedObject/Chain.java
|
||||
* @run main SignedObjectChain
|
||||
*/
|
||||
public class SignedObjectChain {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2017, 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,15 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 6578647 6829283 8171340
|
||||
* @modules java.base/sun.security.util
|
||||
* java.security.jgss/sun.security.krb5.internal:+open
|
||||
* java.security.jgss/sun.security.jgss
|
||||
* java.security.jgss/sun.security.krb5:+open
|
||||
* java.security.jgss/sun.security.krb5.internal.crypto
|
||||
* java.security.jgss/sun.security.krb5.internal.ktab
|
||||
* jdk.security.auth
|
||||
* jdk.security.jgss
|
||||
* jdk.httpserver
|
||||
* @run main/othervm HttpNegotiateServer
|
||||
* @summary Undefined requesting URL in java.net.Authenticator
|
||||
* .getPasswordAuthentication()
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017 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
|
||||
@ -26,12 +26,6 @@
|
||||
* @bug 8058290
|
||||
* @summary JAAS Krb5LoginModule has suspect ticket-renewal logic,
|
||||
* relies on clockskew grace
|
||||
* @modules java.base/sun.security.util
|
||||
* java.security.jgss/sun.security.krb5:+open
|
||||
* java.security.jgss/sun.security.krb5.internal:+open
|
||||
* java.security.jgss/sun.security.krb5.internal.ccache
|
||||
* java.security.jgss/sun.security.krb5.internal.crypto
|
||||
* java.security.jgss/sun.security.krb5.internal.ktab
|
||||
* @compile -XDignore.symbol.file Renew.java
|
||||
* @run main/othervm Renew 1
|
||||
* @run main/othervm Renew 2
|
||||
|
@ -6,4 +6,6 @@ modules java.base/jdk.internal.misc \
|
||||
java.security.jgss/sun.security.krb5.internal.ccache \
|
||||
java.security.jgss/sun.security.krb5.internal.rcache \
|
||||
java.security.jgss/sun.security.krb5.internal.crypto \
|
||||
java.security.jgss/sun.security.krb5.internal.ktab
|
||||
java.security.jgss/sun.security.krb5.internal.ktab \
|
||||
jdk.security.auth \
|
||||
jdk.security.jgss
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, 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,9 +24,10 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 8050374
|
||||
* @summary Verify a chain of signed objects
|
||||
* @compile ../../../java/security/SignedObject/Chain.java
|
||||
* @requires os.family == "windows"
|
||||
* @summary Verify a chain of signed objects
|
||||
* @run main SignedObjectChain
|
||||
*/
|
||||
public class SignedObjectChain {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, 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,8 +24,9 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 8050374
|
||||
* @compile ../../../java/security/SignedObject/Chain.java
|
||||
* @summary Verify a chain of signed objects
|
||||
* @compile ../../../java/security/SignedObject/Chain.java
|
||||
* @run main SignedObjectChain
|
||||
*/
|
||||
public class SignedObjectChain {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, 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,8 +24,9 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 8050374
|
||||
* @compile ../../../../java/security/SignedObject/Chain.java
|
||||
* @summary Verify a chain of signed objects
|
||||
* @compile ../../../../java/security/SignedObject/Chain.java
|
||||
* @run main SignedObjectChain
|
||||
*/
|
||||
public class SignedObjectChain {
|
||||
|
||||
|
@ -43,6 +43,7 @@ import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import jdk.test.lib.SecurityTools;
|
||||
import jdk.testlibrary.*;
|
||||
import jdk.testlibrary.JarUtils;
|
||||
import sun.security.pkcs.ContentInfo;
|
||||
@ -66,6 +67,7 @@ import sun.security.x509.X500Name;
|
||||
* java.base/sun.security.util
|
||||
* java.base/sun.security.tools.keytool
|
||||
* @library /lib/testlibrary
|
||||
* @library /test/lib
|
||||
* @run main/timeout=600 TimestampCheck
|
||||
*/
|
||||
public class TimestampCheck {
|
||||
@ -457,6 +459,18 @@ public class TimestampCheck {
|
||||
verify(file, "-J-Djava.security.debug=jar")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldMatch("SignatureException:.*disabled");
|
||||
|
||||
// For 8171319: keytool should print out warnings when reading or
|
||||
// generating cert/cert req using weak algorithms.
|
||||
// Must call keytool the command, otherwise doPrintCert() might not
|
||||
// be able to reset "jdk.certpath.disabledAlgorithms".
|
||||
String sout = SecurityTools.keytool("-printcert -jarfile weak.jar")
|
||||
.stderrShouldContain("The TSA certificate uses a 512-bit RSA key" +
|
||||
" which is considered a security risk.")
|
||||
.getStdout();
|
||||
if (sout.indexOf("weak", sout.indexOf("Timestamp:")) < 0) {
|
||||
throw new RuntimeException("timestamp not weak: " + sout);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkHalfWeak(String file) throws Throwable {
|
||||
|
557
jdk/test/sun/security/tools/keytool/WeakAlg.java
Normal file
557
jdk/test/sun/security/tools/keytool/WeakAlg.java
Normal file
@ -0,0 +1,557 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8171319
|
||||
* @summary keytool should print out warnings when reading or generating
|
||||
* cert/cert req using weak algorithms
|
||||
* @library /test/lib
|
||||
* @modules java.base/sun.security.tools.keytool
|
||||
* java.base/sun.security.tools
|
||||
* java.base/sun.security.util
|
||||
* @run main/othervm/timeout=600 -Duser.language=en -Duser.country=US WeakAlg
|
||||
*/
|
||||
|
||||
import jdk.test.lib.SecurityTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import sun.security.tools.KeyStoreUtil;
|
||||
import sun.security.util.DisabledAlgorithmConstraints;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.security.CryptoPrimitive;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class WeakAlg {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
|
||||
rm("ks");
|
||||
|
||||
// -genkeypair, and -printcert, -list -alias, -exportcert
|
||||
// (w/ different formats)
|
||||
checkGenKeyPair("a", "-keyalg RSA -sigalg MD5withRSA", "MD5withRSA");
|
||||
checkGenKeyPair("b", "-keyalg RSA -keysize 512", "512-bit RSA key");
|
||||
checkGenKeyPair("c", "-keyalg RSA", null);
|
||||
|
||||
kt("-list")
|
||||
.shouldContain("Warning:")
|
||||
.shouldMatch("<a>.*MD5withRSA.*risk")
|
||||
.shouldMatch("<b>.*512-bit RSA key.*risk");
|
||||
kt("-list -v")
|
||||
.shouldContain("Warning:")
|
||||
.shouldMatch("<a>.*MD5withRSA.*risk")
|
||||
.shouldContain("MD5withRSA (weak)")
|
||||
.shouldMatch("<b>.*512-bit RSA key.*risk")
|
||||
.shouldContain("512-bit RSA key (weak)");
|
||||
|
||||
// Multiple warnings for multiple cert in -printcert or -list or -exportcert
|
||||
|
||||
// -certreq, -printcertreq, -gencert
|
||||
checkCertReq("a", "", null);
|
||||
gencert("c-a", "")
|
||||
.shouldNotContain("Warning"); // new sigalg is not weak
|
||||
gencert("c-a", "-sigalg MD2withRSA")
|
||||
.shouldContain("Warning:")
|
||||
.shouldMatch("The generated certificate.*MD2withRSA.*risk");
|
||||
|
||||
checkCertReq("a", "-sigalg MD5withRSA", "MD5withRSA");
|
||||
gencert("c-a", "")
|
||||
.shouldContain("Warning:")
|
||||
.shouldMatch("The certificate request.*MD5withRSA.*risk");
|
||||
gencert("c-a", "-sigalg MD2withRSA")
|
||||
.shouldContain("Warning:")
|
||||
.shouldMatch("The certificate request.*MD5withRSA.*risk")
|
||||
.shouldMatch("The generated certificate.*MD2withRSA.*risk");
|
||||
|
||||
checkCertReq("b", "", "512-bit RSA key");
|
||||
gencert("c-b", "")
|
||||
.shouldContain("Warning:")
|
||||
.shouldMatch("The certificate request.*512-bit RSA key.*risk")
|
||||
.shouldMatch("The generated certificate.*512-bit RSA key.*risk");
|
||||
|
||||
checkCertReq("c", "", null);
|
||||
gencert("a-c", "")
|
||||
.shouldContain("Warning:")
|
||||
.shouldMatch("The issuer.*MD5withRSA.*risk");
|
||||
|
||||
// but the new cert is not weak
|
||||
kt("-printcert -file a-c.cert")
|
||||
.shouldNotContain("Warning")
|
||||
.shouldNotContain("weak");
|
||||
|
||||
gencert("b-c", "")
|
||||
.shouldContain("Warning:")
|
||||
.shouldMatch("The issuer.*512-bit RSA key.*risk");
|
||||
|
||||
// -importcert
|
||||
checkImport();
|
||||
|
||||
// -importkeystore
|
||||
checkImportKeyStore();
|
||||
|
||||
// -gencrl, -printcrl
|
||||
|
||||
checkGenCRL("a", "", null);
|
||||
checkGenCRL("a", "-sigalg MD5withRSA", "MD5withRSA");
|
||||
checkGenCRL("b", "", "512-bit RSA key");
|
||||
checkGenCRL("c", "", null);
|
||||
|
||||
kt("-delete -alias b");
|
||||
kt("-printcrl -file b.crl")
|
||||
.shouldContain("WARNING: not verified");
|
||||
}
|
||||
|
||||
static void checkImportKeyStore() throws Exception {
|
||||
|
||||
saveStore();
|
||||
|
||||
rm("ks");
|
||||
kt("-importkeystore -srckeystore ks2 -srcstorepass changeit")
|
||||
.shouldContain("3 entries successfully imported")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("<b>.*512-bit RSA key.*risk")
|
||||
.shouldMatch("<a>.*MD5withRSA.*risk");
|
||||
|
||||
rm("ks");
|
||||
kt("-importkeystore -srckeystore ks2 -srcstorepass changeit -srcalias a")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("<a>.*MD5withRSA.*risk");
|
||||
|
||||
reStore();
|
||||
}
|
||||
|
||||
static void checkImport() throws Exception {
|
||||
|
||||
saveStore();
|
||||
|
||||
// add trusted cert
|
||||
|
||||
// cert already in
|
||||
kt("-importcert -alias d -file a.cert", "no")
|
||||
.shouldContain("Certificate already exists in keystore")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("The input.*MD5withRSA.*risk")
|
||||
.shouldContain("Do you still want to add it?");
|
||||
kt("-importcert -alias d -file a.cert -noprompt")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("The input.*MD5withRSA.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
// cert is self-signed
|
||||
kt("-delete -alias a");
|
||||
kt("-delete -alias d");
|
||||
kt("-importcert -alias d -file a.cert", "no")
|
||||
.shouldContain("Warning")
|
||||
.shouldContain("MD5withRSA (weak)")
|
||||
.shouldMatch("The input.*MD5withRSA.*risk")
|
||||
.shouldContain("Trust this certificate?");
|
||||
kt("-importcert -alias d -file a.cert -noprompt")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("The input.*MD5withRSA.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
// cert is self-signed cacerts
|
||||
String weakSigAlgCA = null;
|
||||
KeyStore ks = KeyStoreUtil.getCacertsKeyStore();
|
||||
if (ks != null) {
|
||||
DisabledAlgorithmConstraints disabledCheck =
|
||||
new DisabledAlgorithmConstraints(
|
||||
DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
|
||||
Set<CryptoPrimitive> sigPrimitiveSet = Collections
|
||||
.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
|
||||
|
||||
for (String s : Collections.list(ks.aliases())) {
|
||||
if (ks.isCertificateEntry(s)) {
|
||||
X509Certificate c = (X509Certificate)ks.getCertificate(s);
|
||||
String sigAlg = c.getSigAlgName();
|
||||
if (!disabledCheck.permits(sigPrimitiveSet, sigAlg, null)) {
|
||||
weakSigAlgCA = sigAlg;
|
||||
Files.write(Paths.get("ca.cert"),
|
||||
ks.getCertificate(s).getEncoded());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (weakSigAlgCA != null) {
|
||||
kt("-delete -alias d");
|
||||
kt("-importcert -alias d -trustcacerts -file ca.cert", "no")
|
||||
.shouldContain("Certificate already exists in system-wide CA")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("The input.*" + weakSigAlgCA + ".*risk")
|
||||
.shouldContain("Do you still want to add it to your own keystore?");
|
||||
kt("-importcert -alias d -file ca.cert -noprompt")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("The input.*" + weakSigAlgCA + ".*risk")
|
||||
.shouldNotContain("[no]");
|
||||
}
|
||||
|
||||
// a non self-signed weak cert
|
||||
reStore();
|
||||
certreq("b", "");
|
||||
gencert("c-b", "");
|
||||
kt("-importcert -alias d -file c-b.cert") // weak only, no prompt
|
||||
.shouldContain("Warning")
|
||||
.shouldNotContain("512-bit RSA key (weak)")
|
||||
.shouldMatch("The input.*512-bit RSA key.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
kt("-delete -alias b");
|
||||
kt("-delete -alias c");
|
||||
kt("-delete -alias d");
|
||||
|
||||
kt("-importcert -alias d -file c-b.cert", "no") // weak and not trusted
|
||||
.shouldContain("Warning")
|
||||
.shouldContain("512-bit RSA key (weak)")
|
||||
.shouldMatch("The input.*512-bit RSA key.*risk")
|
||||
.shouldContain("Trust this certificate?");
|
||||
kt("-importcert -alias d -file c-b.cert -noprompt")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("The input.*512-bit RSA key.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
// a non self-signed strong cert
|
||||
reStore();
|
||||
certreq("a", "");
|
||||
gencert("c-a", "");
|
||||
kt("-importcert -alias d -file c-a.cert") // trusted
|
||||
.shouldNotContain("Warning")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
kt("-delete -alias a");
|
||||
kt("-delete -alias c");
|
||||
kt("-delete -alias d");
|
||||
|
||||
kt("-importcert -alias d -file c-a.cert", "no") // not trusted
|
||||
.shouldNotContain("Warning")
|
||||
.shouldContain("Trust this certificate?");
|
||||
kt("-importcert -alias d -file c-a.cert -noprompt")
|
||||
.shouldNotContain("Warning")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
// install reply
|
||||
|
||||
reStore();
|
||||
|
||||
gencert("a-b", "");
|
||||
gencert("b-c", "");
|
||||
|
||||
// Full chain with root
|
||||
cat("a-a-b-c.cert", "b-c.cert", "a-b.cert", "a.cert");
|
||||
kt("-importcert -alias c -file a-a-b-c.cert") // only weak
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("Reply #2 of 3.*512-bit RSA key.*risk")
|
||||
.shouldMatch("Reply #3 of 3.*MD5withRSA.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
// Without root
|
||||
cat("a-b-c.cert", "b-c.cert", "a-b.cert");
|
||||
kt("-importcert -alias c -file a-b-c.cert") // only weak
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("Reply #2 of 2.*512-bit RSA key.*risk")
|
||||
.shouldMatch("Issuer <a>.*MD5withRSA.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
reStore();
|
||||
gencert("b-a", "");
|
||||
|
||||
kt("-importcert -alias a -file b-a.cert")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("Issuer <b>.*512-bit RSA key.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
kt("-importcert -alias a -file c-a.cert")
|
||||
.shouldNotContain("Warning");
|
||||
|
||||
kt("-importcert -alias b -file c-b.cert")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("The input.*512-bit RSA key.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
reStore();
|
||||
gencert("b-a", "");
|
||||
|
||||
cat("c-b-a.cert", "b-a.cert", "c-b.cert");
|
||||
|
||||
kt("-printcert -file c-b-a.cert")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("The certificate #2 of 2.*512-bit RSA key.*risk");
|
||||
|
||||
kt("-delete -alias b");
|
||||
|
||||
kt("-importcert -alias a -file c-b-a.cert")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("Reply #2 of 2.*512-bit RSA key.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
kt("-delete -alias c");
|
||||
kt("-importcert -alias a -file c-b-a.cert", "no")
|
||||
.shouldContain("Top-level certificate in reply:")
|
||||
.shouldContain("512-bit RSA key (weak)")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("Reply #2 of 2.*512-bit RSA key.*risk")
|
||||
.shouldContain("Install reply anyway?");
|
||||
kt("-importcert -alias a -file c-b-a.cert -noprompt")
|
||||
.shouldContain("Warning")
|
||||
.shouldMatch("Reply #2 of 2.*512-bit RSA key.*risk")
|
||||
.shouldNotContain("[no]");
|
||||
|
||||
reStore();
|
||||
}
|
||||
|
||||
private static void cat(String dest, String... src) throws IOException {
|
||||
System.out.println("---------------------------------------------");
|
||||
System.out.printf("$ cat ");
|
||||
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
for (String s : src) {
|
||||
System.out.printf(s + " ");
|
||||
bout.write(Files.readAllBytes(Paths.get(s)));
|
||||
}
|
||||
Files.write(Paths.get(dest), bout.toByteArray());
|
||||
System.out.println("> " + dest);
|
||||
}
|
||||
|
||||
static void checkGenCRL(String alias, String options, String bad) {
|
||||
|
||||
OutputAnalyzer oa = kt("-gencrl -alias " + alias
|
||||
+ " -id 1 -file " + alias + ".crl " + options);
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldMatch("The generated CRL.*" + bad + ".*risk");
|
||||
}
|
||||
|
||||
oa = kt("-printcrl -file " + alias + ".crl");
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning")
|
||||
.shouldContain("Verified by " + alias + " in keystore")
|
||||
.shouldNotContain("(weak");
|
||||
} else {
|
||||
oa.shouldContain("Warning:")
|
||||
.shouldMatch("The CRL.*" + bad + ".*risk")
|
||||
.shouldContain("Verified by " + alias + " in keystore")
|
||||
.shouldContain(bad + " (weak)");
|
||||
}
|
||||
}
|
||||
|
||||
static void checkCertReq(
|
||||
String alias, String options, String bad) {
|
||||
|
||||
OutputAnalyzer oa = certreq(alias, options);
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldMatch("The generated certificate request.*" + bad + ".*risk");
|
||||
}
|
||||
|
||||
oa = kt("-printcertreq -file " + alias + ".req");
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning")
|
||||
.shouldNotContain("(weak)");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldMatch("The certificate request.*" + bad + ".*risk")
|
||||
.shouldContain(bad + " (weak)");
|
||||
}
|
||||
}
|
||||
|
||||
static void checkGenKeyPair(
|
||||
String alias, String options, String bad) {
|
||||
|
||||
OutputAnalyzer oa = genkeypair(alias, options);
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldMatch("The generated certificate.*" + bad + ".*risk");
|
||||
}
|
||||
|
||||
oa = kt("-exportcert -alias " + alias + " -file " + alias + ".cert");
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldMatch("The certificate.*" + bad + ".*risk");
|
||||
}
|
||||
|
||||
oa = kt("-exportcert -rfc -alias " + alias + " -file " + alias + ".cert");
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldMatch("The certificate.*" + bad + ".*risk");
|
||||
}
|
||||
|
||||
oa = kt("-printcert -rfc -file " + alias + ".cert");
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldMatch("The certificate.*" + bad + ".*risk");
|
||||
}
|
||||
|
||||
oa = kt("-list -alias " + alias);
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldMatch("The certificate.*" + bad + ".*risk");
|
||||
}
|
||||
|
||||
// With cert content
|
||||
|
||||
oa = kt("-printcert -file " + alias + ".cert");
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldContain(bad + " (weak)")
|
||||
.shouldMatch("The certificate.*" + bad + ".*risk");
|
||||
}
|
||||
|
||||
oa = kt("-list -v -alias " + alias);
|
||||
if (bad == null) {
|
||||
oa.shouldNotContain("Warning");
|
||||
} else {
|
||||
oa.shouldContain("Warning")
|
||||
.shouldContain(bad + " (weak)")
|
||||
.shouldMatch("The certificate.*" + bad + ".*risk");
|
||||
}
|
||||
}
|
||||
|
||||
// This is slow, but real keytool process is launched.
|
||||
static OutputAnalyzer kt1(String cmd, String... input) {
|
||||
cmd = "-keystore ks -storepass changeit " +
|
||||
"-keypass changeit " + cmd;
|
||||
System.out.println("---------------------------------------------");
|
||||
try {
|
||||
SecurityTools.setResponse(input);
|
||||
return SecurityTools.keytool(cmd);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Fast keytool execution by directly calling its main() method
|
||||
static OutputAnalyzer kt(String cmd, String... input) {
|
||||
PrintStream out = System.out;
|
||||
PrintStream err = System.err;
|
||||
InputStream ins = System.in;
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream berr = new ByteArrayOutputStream();
|
||||
boolean succeed = true;
|
||||
try {
|
||||
cmd = "-keystore ks -storepass changeit " +
|
||||
"-keypass changeit " + cmd;
|
||||
System.out.println("---------------------------------------------");
|
||||
System.out.println("$ keytool " + cmd);
|
||||
System.out.println();
|
||||
String feed = "";
|
||||
if (input.length > 0) {
|
||||
feed = Stream.of(input).collect(Collectors.joining("\n")) + "\n";
|
||||
}
|
||||
System.setIn(new ByteArrayInputStream(feed.getBytes()));
|
||||
System.setOut(new PrintStream(bout));
|
||||
System.setErr(new PrintStream(berr));
|
||||
sun.security.tools.keytool.Main.main(
|
||||
cmd.trim().split("\\s+"));
|
||||
} catch (Exception e) {
|
||||
// Might be a normal exception when -debug is on or
|
||||
// SecurityException (thrown by jtreg) when System.exit() is called
|
||||
if (!(e instanceof SecurityException)) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
succeed = false;
|
||||
} finally {
|
||||
System.setOut(out);
|
||||
System.setErr(err);
|
||||
System.setIn(ins);
|
||||
}
|
||||
String sout = new String(bout.toByteArray());
|
||||
String serr = new String(berr.toByteArray());
|
||||
System.out.println("STDOUT:\n" + sout + "\nSTDERR:\n" + serr);
|
||||
if (!succeed) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
return new OutputAnalyzer(sout, serr);
|
||||
}
|
||||
|
||||
static OutputAnalyzer genkeypair(String alias, String options) {
|
||||
return kt("-genkeypair -alias " + alias + " -dname CN=" + alias
|
||||
+ " -keyalg RSA -storetype JKS " + options);
|
||||
}
|
||||
|
||||
static OutputAnalyzer certreq(String alias, String options) {
|
||||
return kt("-certreq -alias " + alias
|
||||
+ " -file " + alias + ".req " + options);
|
||||
}
|
||||
|
||||
static OutputAnalyzer exportcert(String alias) {
|
||||
return kt("-exportcert -alias " + alias + " -file " + alias + ".cert");
|
||||
}
|
||||
|
||||
static OutputAnalyzer gencert(String relation, String options) {
|
||||
int pos = relation.indexOf("-");
|
||||
String issuer = relation.substring(0, pos);
|
||||
String subject = relation.substring(pos + 1);
|
||||
return kt(" -gencert -alias " + issuer + " -infile " + subject
|
||||
+ ".req -outfile " + relation + ".cert " + options);
|
||||
}
|
||||
|
||||
static void saveStore() throws IOException {
|
||||
System.out.println("---------------------------------------------");
|
||||
System.out.println("$ cp ks ks2");
|
||||
Files.copy(Paths.get("ks"), Paths.get("ks2"),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
static void reStore() throws IOException {
|
||||
System.out.println("---------------------------------------------");
|
||||
System.out.println("$ cp ks2 ks");
|
||||
Files.copy(Paths.get("ks2"), Paths.get("ks"),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
static void rm(String s) throws IOException {
|
||||
System.out.println("---------------------------------------------");
|
||||
System.out.println("$ rm " + s);
|
||||
Files.deleteIfExists(Paths.get(s));
|
||||
}
|
||||
}
|
80
jdk/test/tools/launcher/Jexec.java
Normal file
80
jdk/test/tools/launcher/Jexec.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8175000
|
||||
* @summary test jexec
|
||||
* @build TestHelper
|
||||
* @run main Jexec
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Jexec extends TestHelper {
|
||||
private final File testJar;
|
||||
private final File jexecCmd;
|
||||
private final String message = "Hello, do you read me ?";
|
||||
|
||||
Jexec() throws IOException {
|
||||
jexecCmd = new File(JAVA_LIB, "jexec");
|
||||
if (!jexecCmd.exists() || !jexecCmd.canExecute()) {
|
||||
throw new Error("jexec: does not exist or not executable");
|
||||
}
|
||||
|
||||
testJar = new File("test.jar");
|
||||
StringBuilder tsrc = new StringBuilder();
|
||||
tsrc.append("public static void main(String... args) {\n");
|
||||
tsrc.append(" for (String x : args) {\n");
|
||||
tsrc.append(" System.out.println(x);\n");
|
||||
tsrc.append(" }\n");
|
||||
tsrc.append("}\n");
|
||||
createJar(testJar, tsrc.toString());
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
// linux is the only supported platform, give the others a pass
|
||||
if (!isLinux) {
|
||||
System.err.println("Warning: unsupported platform test passes vacuously");
|
||||
return;
|
||||
}
|
||||
// ok to run the test now
|
||||
Jexec t = new Jexec();
|
||||
t.run(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void jexec() throws Exception {
|
||||
TestResult tr = doExec(jexecCmd.getAbsolutePath(),
|
||||
testJar.getAbsolutePath(), message);
|
||||
if (!tr.isOK()) {
|
||||
System.err.println(tr);
|
||||
throw new Exception("incorrect exit value");
|
||||
}
|
||||
if (!tr.contains(message)) {
|
||||
System.err.println(tr);
|
||||
throw new Exception("expected message \'" + message + "\' not found");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user