Project: javamail
Repository: mercurial
Revision: 804
Author: shannon
Date: 2015-12-02 21:30:36 UTC
Link:
Log Message:
------------
skip terminating ')' in string list - bug 7090
CollectorFormatter descending order data race - Bug 7083
Revisions:
----------
803
804
Modified Paths:
---------------
doc/release/CHANGES.txt
mail/src/main/java/com/sun/mail/iap/Response.java
mail/src/test/java/com/sun/mail/iap/ResponseTest.java
mail/src/main/java/com/sun/mail/util/logging/CollectorFormatter.java
mail/src/test/java/com/sun/mail/util/logging/CollectorFormatterTest.java
Diffs:
------
diff -r 462b6507d18a -r 1e8457095a27 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Nov 20 15:58:27 2015 -0800
+++ b/doc/release/CHANGES.txt Wed Dec 02 13:02:12 2015 -0800
@@ -42,6 +42,8 @@
K 7052 Empty Gmail X-GM-LABELS list is misparsed
K 7075 IMAPMessage.getReceivedDate should check if receivedDate is present
before loading envelope
+K 7090 off-by-1 error in Response.readStringList causes early termination of
+ parsing FETCH response
CHANGES IN THE 1.5.4 RELEASE
diff -r 462b6507d18a -r 1e8457095a27 mail/src/main/java/com/sun/mail/iap/Response.java
--- a/mail/src/main/java/com/sun/mail/iap/Response.java Fri Nov 20 15:58:27 2015 -0800
+++ b/mail/src/main/java/com/sun/mail/iap/Response.java Wed Dec 02 13:02:12 2015 -0800
@@ -292,8 +292,9 @@
if (peekByte() != ')') {
do {
result.add(atom ? readAtomString() : readString());
- } while (buffer[index++] != ')');
- }
+ } while (index < size && buffer[index++] != ')');
+ } else
+ index++; // skip ')'
return result.toArray(new String[result.size()]);
}
diff -r 462b6507d18a -r 1e8457095a27 mail/src/test/java/com/sun/mail/iap/ResponseTest.java
--- a/mail/src/test/java/com/sun/mail/iap/ResponseTest.java Fri Nov 20 15:58:27 2015 -0800
+++ b/mail/src/test/java/com/sun/mail/iap/ResponseTest.java Wed Dec 02 13:02:12 2015 -0800
@@ -109,6 +109,17 @@
}
/**
+ * Test astring lists with more data following.
+ */
+ @Test
+ public void testAStringListMore() throws Exception {
+ Response r = new Response("* " + "(A B \"C\") atom");
+ assertArrayEquals(new String[] { "A", "B", "C" },
+ r.readAtomStringList());
+ assertEquals("atom", r.readAtomString());
+ }
+
+ /**
* Test empty astring lists.
*/
@Test
@@ -116,4 +127,14 @@
Response r = new Response("* " + "()");
assertArrayEquals(new String[0], r.readAtomStringList());
}
+
+ /**
+ * Test empty astring lists with more data following.
+ */
+ @Test
+ public void testAStringListEmptyMore() throws Exception {
+ Response r = new Response("* " + "() atom");
+ assertArrayEquals(new String[0], r.readAtomStringList());
+ assertEquals("atom", r.readAtomString());
+ }
}
diff -r 1e8457095a27 -r 122c7b3a6fdb doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Wed Dec 02 13:02:12 2015 -0800
+++ b/doc/release/CHANGES.txt Wed Dec 02 13:30:36 2015 -0800
@@ -42,6 +42,7 @@
K 7052 Empty Gmail X-GM-LABELS list is misparsed
K 7075 IMAPMessage.getReceivedDate should check if receivedDate is present
before loading envelope
+K 7083 CollectorFormatter descending order data race
K 7090 off-by-1 error in Response.readStringList causes early termination of
parsing FETCH response
diff -r 1e8457095a27 -r 122c7b3a6fdb mail/src/main/java/com/sun/mail/util/logging/CollectorFormatter.java
--- a/mail/src/main/java/com/sun/mail/util/logging/CollectorFormatter.java Wed Dec 02 13:02:12 2015 -0800
+++ b/mail/src/main/java/com/sun/mail/util/logging/CollectorFormatter.java Wed Dec 02 13:30:36 2015 -0800
@@ -209,8 +209,7 @@
update.getSourceMethodName(); //Infer caller, null check.
accepted = acceptAndUpdate(peek, update);
} else {
- accepted = true;
- accept(record);
+ accepted = accept(peek, record);
}
} while (!accepted);
return "";
@@ -368,21 +367,36 @@
}
/**
- * Updates the summary statistics but does not store the given LogRecord.
+ * Updates the summary statistics only if the expected record matches the
+ * last record. The update record is not stored.
*
- * @param record the LogRecord used to collect statistics.
+ * @param e the LogRecord that is expected.
+ * @param u the LogRecord used to collect statistics.
+ * @return true if the last record was the expected record.
+ * @throws NullPointerException if the update record is null.
*/
- private synchronized void accept(final LogRecord record) {
- final long millis = record.getMillis();
- if (++count != 1L) {
- minMillis = Math.min(minMillis, millis);
- } else { //Show single records as instant and not a time period.
- minMillis = millis;
- }
- maxMillis = Math.max(maxMillis, millis);
+ private synchronized boolean accept(final LogRecord e, final LogRecord u) {
+ /**
+ * LogRecord methods must be called before the check of the last stored
+ * record to guard against subclasses of LogRecord that might attempt to
+ * reset the state by triggering a call to getTail.
+ */
+ final long millis = u.getMillis(); //Null check.
+ final Throwable ex = u.getThrown();
+ if (last == e) { //Only if the exact same reference.
+ if (++count != 1L) {
+ minMillis = Math.min(minMillis, millis);
+ } else { //Show single records as instant and not a time period.
+ minMillis = millis;
+ }
+ maxMillis = Math.max(maxMillis, millis);
- if (record.getThrown() != null) {
- ++thrown;
+ if (ex != null) {
+ ++thrown;
+ }
+ return true;
+ } else {
+ return false;
}
}
@@ -501,10 +515,10 @@
* @param e the expected record.
* @param u the update record.
* @return true if the update was performed.
+ * @throws NullPointerException if the update record is null.
*/
private synchronized boolean acceptAndUpdate(LogRecord e, LogRecord u) {
- if (e == this.last) {
- accept(u);
+ if (accept(e, u)) {
this.last = u;
return true;
} else {
diff -r 1e8457095a27 -r 122c7b3a6fdb mail/src/test/java/com/sun/mail/util/logging/CollectorFormatterTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/CollectorFormatterTest.java Wed Dec 02 13:02:12 2015 -0800
+++ b/mail/src/test/java/com/sun/mail/util/logging/CollectorFormatterTest.java Wed Dec 02 13:30:36 2015 -0800
@@ -154,6 +154,93 @@
f.format((LogRecord) null);
}
+ private static final class TestFormatterAccept extends LogRecord {
+
+ private static final long serialVersionUID = 1L;
+
+ int inferred;
+ private transient Formatter f;
+
+ TestFormatterAccept(Level level, CollectorFormatter f) {
+ super(level, "");
+ this.f = f;
+ }
+
+ @Override
+ public Throwable getThrown() {
+ if (inferred == 0) {
+ assertEquals(Level.INFO.getLocalizedName().concat("11111"),
+ f.getTail((Handler) null));
+ }
+ return super.getThrown();
+ }
+
+ @Override
+ public String getSourceMethodName() {
+ ++inferred;
+ return super.getSourceMethodName();
+ }
+ }
+
+ @Test(timeout = 60000)
+ public void testFormatAccept() throws Exception {
+ final CollectorFormatter f = new CollectorFormatter(
+ "{1}{3}{5}{7}{8}{13}",
+ new CompactFormatter("%4$s"),
+ new SeverityComparator());
+ LogRecord first = new LogRecord(Level.INFO, "");
+ first.setThrown(new Throwable());
+ first.setMillis(1L);
+ f.format(first);
+
+ TestFormatterAccept r = new TestFormatterAccept(Level.FINE, f);
+ r.setMillis(2L);
+ r.setThrown(new Throwable());
+ f.format(r);
+ assertEquals(1, r.inferred);
+ assertEquals(Level.FINE.getLocalizedName().concat("11222"),
+ f.getTail((Handler) null));
+ }
+
+ private static final class TestFormatAcceptAndUpdate extends LogRecord {
+
+ private static final long serialVersionUID = 1L;
+ int inferred;
+ private transient Formatter f;
+
+ public TestFormatAcceptAndUpdate(Level level, CollectorFormatter f) {
+ super(level, "");
+ this.f = f;
+ }
+
+ @Override
+ public String getSourceMethodName() {
+ if (++inferred == 1) {
+ LogRecord r = new LogRecord(Level.INFO, "");
+ r.setMillis(1L);
+ f.format(r);
+ }
+ return super.getSourceMethodName();
+ }
+ }
+
+ @Test(timeout = 60000)
+ public void testFormatAcceptAndUpdate() throws Exception {
+ final CollectorFormatter f = new CollectorFormatter(
+ "{1}{3}{5}{7}{8}{13}",
+ new CompactFormatter("%4$s"),
+ new SeverityComparator());
+
+ TestFormatAcceptAndUpdate r
+ = new TestFormatAcceptAndUpdate(Level.SEVERE, f);
+ r.setMillis(2L);
+ r.setThrown(new Throwable());
+ f.format(r);
+ assertEquals(2, r.inferred);
+ assertEquals(Level.SEVERE.getLocalizedName().concat("21121"),
+ f.getTail((Handler) null));
+ }
+
@Test
public void testFormatFormat() {
String msg = "message";
@@ -575,7 +662,6 @@
String output = cf.getTail((Handler) null);
assertNotNull(output);
-
cf.format(min);
for (int i = 0; i < 114; ++i) {
LogRecord mid = new LogRecord(Level.SEVERE, "");
@@ -583,7 +669,6 @@
cf.format(mid);
}
-
max.setMillis(min.getMillis() + 2591000000L);
cf.format(max);
@@ -816,7 +901,6 @@
assertEquals(75, n.longValue());
}
-
@Test
public void testFormatInitTimeMillis() throws Exception {
CollectorFormatter f = new CollectorFormatter("{10}", (Formatter) null,
@@ -832,7 +916,7 @@
@Test
public void testFormatInitTimeDateTime() throws Exception {
CollectorFormatter f = new CollectorFormatter(
- "{10,date,"+DATE_TIME_FMT+"}",
+ "{10,date," + DATE_TIME_FMT + "}",
(Formatter) null,
(Comparator<LogRecord>) null);
@@ -860,7 +944,7 @@
@Test
public void testFormatCurrentTimeDateTime() throws Exception {
CollectorFormatter f = new CollectorFormatter(
- "{11,date,"+DATE_TIME_FMT+"}",
+ "{11,date," + DATE_TIME_FMT + "}",
(Formatter) null,
(Comparator<LogRecord>) null);
@@ -964,6 +1048,7 @@
* An example of a broken implementation of apply.
*/
private static class ApplyReturnsNull extends CollectorFormatter {
+
/**
* The number of records.
*/