merge in nyc-dr1-release history after reset to nyc-dr1-dev
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 2dd0bb5..0aca53e 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -19,8 +19,11 @@
import junit.framework.TestCase;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collections;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
@@ -392,6 +395,54 @@
assertEquals("Getter iterations", iterations, getterCount.get());
}
+ // http://b/30979219
+ public void testSetDefaultRace() throws InterruptedException {
+ // Since this tests a race condition, the test is probabilistic: it's not guaranteed to
+ // fail if the problem exists
+
+ // These iterations are significantly faster than the ones in #testSetDefaultDeadlock
+ final int iterations = 10000;
+ List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<>());
+ Thread.UncaughtExceptionHandler handler = (t, e) -> exceptions.add(e);
+
+ CyclicBarrier startBarrier = new CyclicBarrier(2);
+ Thread clearer = new Thread(() -> {
+ waitFor(startBarrier);
+ for (int i = 0; i < iterations; i++) {
+ // This is not public API but can effectively be invoked via
+ // java.util.TimeZone.setDefault. Call it directly to reduce the amount of code
+ // involved in this test.
+ android.icu.util.TimeZone.clearCachedDefault();
+ }
+ });
+ clearer.setName("testSetDefaultRace clearer");
+ clearer.setUncaughtExceptionHandler(handler);
+
+ Thread getter = new Thread(() -> {
+ waitFor(startBarrier);
+ for (int i = 0; i < iterations; i++) {
+ android.icu.util.TimeZone.getDefault();
+ }
+ });
+ getter.setName("testSetDefaultRace getter");
+ getter.setUncaughtExceptionHandler(handler);
+
+ clearer.start();
+ getter.start();
+
+ // 2 seconds is plenty: If successful, we usually complete much faster.
+ clearer.join(1000);
+ getter.join(1000);
+
+ if (!exceptions.isEmpty()) {
+ Throwable firstException = exceptions.get(0);
+ firstException.printStackTrace();
+ fail("Threads did not succeed successfully: " + firstException);
+ }
+ assertFalse("clearer thread is still alive", clearer.isAlive());
+ assertFalse("getter thread is still alive", getter.isAlive());
+ }
+
private static void waitFor(CyclicBarrier barrier) {
try {
barrier.await();
diff --git a/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java b/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
index 4f5d658..5471b1f 100644
--- a/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
+++ b/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
@@ -120,6 +120,30 @@
expectExceptionInDNConstructor("l=\\g0");
}
+ public void testNegativeLen() {
+ try {
+ X500Principal p = new X500Principal(new byte[]{
+ 0x30, // DerValue.tag_Sequence read in DerValue#getSequence
+ 9, // Length of the vector. read in readVector.
+ // DerInputStream.getLength will just return this as 10 & 0x80 == 0
+ -1, // Tag of the first value in the sequencevalue. Convenient so that it
+ // doesn't hold DerIndefLenConverter.isEOC()
+ (byte) 0x80, // Encoding in indefinite form
+ -1, // Second tag to be read by DerIndefLenConverter
+ (byte) 0x84, // Second length byte to be read, 0x80 means long form, 4 bytes
+ (byte) 0xff, // Length to be read by DerIndefLenConverter, -6, will move the
+ // buffer position to the second tag
+ (byte) 0xff,
+ (byte) 0xff,
+ (byte) -6,
+ 0, // Needed as otherwise it's detected that there's nothing after
+ // the length
+ });
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
private void expectExceptionInDNConstructor(String dn) {
try {
X500Principal principal = new X500Principal(dn);
diff --git a/ojluni/src/main/java/sun/security/util/DerIndefLenConverter.java b/ojluni/src/main/java/sun/security/util/DerIndefLenConverter.java
index 78d9e30..cbd5ecc 100755
--- a/ojluni/src/main/java/sun/security/util/DerIndefLenConverter.java
+++ b/ojluni/src/main/java/sun/security/util/DerIndefLenConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -156,12 +156,18 @@
}
if (isLongForm(lenByte)) {
lenByte &= LEN_MASK;
- if (lenByte > 4)
+ if (lenByte > 4) {
throw new IOException("Too much data");
- if ((dataSize - dataPos) < (lenByte + 1))
+ }
+ if ((dataSize - dataPos) < (lenByte + 1)) {
throw new IOException("Too little data");
- for (int i = 0; i < lenByte; i++)
+ }
+ for (int i = 0; i < lenByte; i++) {
curLen = (curLen << 8) + (data[dataPos++] & 0xff);
+ }
+ if (curLen < 0) {
+ throw new IOException("Invalid length bytes");
+ }
} else {
curLen = (lenByte & LEN_MASK);
}
@@ -188,10 +194,15 @@
}
if (isLongForm(lenByte)) {
lenByte &= LEN_MASK;
- for (int i = 0; i < lenByte; i++)
+ for (int i = 0; i < lenByte; i++) {
curLen = (curLen << 8) + (data[dataPos++] & 0xff);
- } else
+ }
+ if (curLen < 0) {
+ throw new IOException("Invalid length bytes");
+ }
+ } else {
curLen = (lenByte & LEN_MASK);
+ }
writeLength(curLen);
writeValue(curLen);
}
diff --git a/ojluni/src/main/java/sun/security/util/DerInputStream.java b/ojluni/src/main/java/sun/security/util/DerInputStream.java
index 8f51439..dae8afd 100755
--- a/ojluni/src/main/java/sun/security/util/DerInputStream.java
+++ b/ojluni/src/main/java/sun/security/util/DerInputStream.java
@@ -604,6 +604,10 @@
value <<= 8;
value += 0x0ff & in.read();
}
+ if (value < 0) {
+ throw new IOException("DerInputStream.getLength(): "
+ + "Invalid length bytes");
+ }
}
return value;
}