undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.XMLFormatter;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8072645
|
||||
* @summary tests that XmlFormatter will print out dates with the new
|
||||
* nanosecond precision.
|
||||
* @run main/othervm XmlFormatterNanos
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class XmlFormatterNanos {
|
||||
|
||||
static final int MILLIS_IN_SECOND = 1000;
|
||||
static final int NANOS_IN_MILLI = 1000_000;
|
||||
static final int NANOS_IN_MICRO = 1000;
|
||||
static final int NANOS_IN_SECOND = 1000_000_000;
|
||||
|
||||
static final boolean verbose = true;
|
||||
|
||||
static final class TestAssertException extends RuntimeException {
|
||||
TestAssertException(String msg) { super(msg); }
|
||||
}
|
||||
|
||||
private static void assertEquals(long expected, long received, String msg) {
|
||||
if (expected != received) {
|
||||
throw new TestAssertException("Unexpected result for " + msg
|
||||
+ ".\n\texpected: " + expected
|
||||
+ "\n\tactual: " + received);
|
||||
} else if (verbose) {
|
||||
System.out.println("Got expected " + msg + ": " + received);
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertEquals(Object expected, Object received, String msg) {
|
||||
if (!Objects.equals(expected, received)) {
|
||||
throw new TestAssertException("Unexpected result for " + msg
|
||||
+ ".\n\texpected: " + expected
|
||||
+ "\n\tactual: " + received);
|
||||
} else if (verbose) {
|
||||
System.out.println("Got expected " + msg + ": " + received);
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomXMLFormatter extends XMLFormatter {}
|
||||
|
||||
static class Configuration {
|
||||
final Properties propertyFile;
|
||||
private Configuration(Properties properties) {
|
||||
propertyFile = properties;
|
||||
}
|
||||
public Configuration apply() {
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
propertyFile.store(bytes, testName());
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes.toByteArray());
|
||||
LogManager.getLogManager().readConfiguration(bais);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public static String useInstantProperty(Class<?> type) {
|
||||
return type.getName()+".useInstant";
|
||||
}
|
||||
|
||||
public boolean useInstant(XMLFormatter formatter) {
|
||||
return Boolean.parseBoolean(propertyFile.getProperty(
|
||||
formatter.getClass().getName()+".useInstant", "true"));
|
||||
}
|
||||
|
||||
public String testName() {
|
||||
return propertyFile.getProperty("test.name", "????");
|
||||
}
|
||||
|
||||
public static Configuration of(Properties props) {
|
||||
return new Configuration(props);
|
||||
}
|
||||
|
||||
public static Configuration apply(Properties props) {
|
||||
return of(props).apply();
|
||||
}
|
||||
}
|
||||
|
||||
static final List<Properties> properties;
|
||||
static {
|
||||
Properties props1 = new Properties();
|
||||
props1.setProperty("test.name", "with XML nano element (default)");
|
||||
Properties props2 = new Properties();
|
||||
props2.setProperty("test.name", "with XML nano element (standard=true, custom=false)");
|
||||
props2.setProperty(Configuration.useInstantProperty(XMLFormatter.class), "true");
|
||||
props2.setProperty(Configuration.useInstantProperty(CustomXMLFormatter.class), "false");
|
||||
Properties props3 = new Properties();
|
||||
props3.setProperty("test.name", "with XML nano element (standard=false, custom=true)");
|
||||
props3.setProperty(Configuration.useInstantProperty(XMLFormatter.class), "false");
|
||||
props3.setProperty(Configuration.useInstantProperty(CustomXMLFormatter.class), "true");
|
||||
|
||||
properties = Collections.unmodifiableList(Arrays.asList(
|
||||
props1,
|
||||
props2));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Locale.setDefault(Locale.ENGLISH);
|
||||
properties.stream().forEach(XmlFormatterNanos::test);
|
||||
}
|
||||
|
||||
static int getNanoAdjustment(LogRecord record) {
|
||||
return record.getInstant().getNano() % NANOS_IN_MILLI;
|
||||
}
|
||||
static void setNanoAdjustment(LogRecord record, int nanos) {
|
||||
record.setInstant(Instant.ofEpochSecond(record.getInstant().getEpochSecond(),
|
||||
(record.getInstant().getNano() / NANOS_IN_MILLI) * NANOS_IN_MILLI + nanos));
|
||||
}
|
||||
|
||||
public static void test(Properties props) {
|
||||
Configuration conf = Configuration.apply(props);
|
||||
|
||||
LogRecord record = new LogRecord(Level.INFO, "Test Name: {0}");
|
||||
record.setLoggerName("test");
|
||||
record.setParameters(new Object[] {conf.testName()});
|
||||
int nanos = record.getInstant().getNano() % NANOS_IN_MILLI;
|
||||
long millis = record.getMillis();
|
||||
// make sure we don't have leading zeros when printing below
|
||||
// the second precision
|
||||
if (millis % MILLIS_IN_SECOND < 100) millis = millis + 100;
|
||||
// make sure we some nanos - and make sure we don't have
|
||||
// trailing zeros
|
||||
if (nanos % 10 == 0) nanos = nanos + 7;
|
||||
|
||||
record.setMillis(millis);
|
||||
setNanoAdjustment(record, nanos);
|
||||
final Instant instant = record.getInstant();
|
||||
if (nanos < 0) {
|
||||
throw new RuntimeException("Unexpected negative nano adjustment: "
|
||||
+ getNanoAdjustment(record));
|
||||
}
|
||||
if (nanos >= NANOS_IN_MILLI) {
|
||||
throw new RuntimeException("Nano adjustment exceeds 1ms: "
|
||||
+ getNanoAdjustment(record));
|
||||
}
|
||||
if (millis != record.getMillis()) {
|
||||
throw new RuntimeException("Unexpected millis: " + millis + " != "
|
||||
+ record.getMillis());
|
||||
}
|
||||
if (millis != record.getInstant().toEpochMilli()) {
|
||||
throw new RuntimeException("Unexpected millis: "
|
||||
+ record.getInstant().toEpochMilli());
|
||||
}
|
||||
long expectedNanos = (millis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + nanos;
|
||||
assertEquals(expectedNanos, instant.getNano(), "Instant.getNano()");
|
||||
|
||||
XMLFormatter formatter = new XMLFormatter();
|
||||
testMatching(formatter, record, instant, expectedNanos, conf.useInstant(formatter));
|
||||
|
||||
XMLFormatter custom = new CustomXMLFormatter();
|
||||
testMatching(custom, record, instant, expectedNanos, conf.useInstant(custom));
|
||||
}
|
||||
|
||||
private static void testMatching(XMLFormatter formatter,
|
||||
LogRecord record, Instant instant, long expectedNanos,
|
||||
boolean useInstant) {
|
||||
|
||||
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
int zdtNanos = zdt.getNano();
|
||||
assertEquals(expectedNanos, zdtNanos, "ZonedDateTime.getNano()");
|
||||
|
||||
String str = formatter.format(record);
|
||||
|
||||
String match = "."+expectedNanos;
|
||||
if (str.contains(match) != useInstant) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string does not contain expected nanos: "
|
||||
+ "\n\texpected match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
System.out.println("Found expected match for '"+match+"' in \n"+str);
|
||||
|
||||
match = "<millis>"+instant.toEpochMilli()+"</millis>";
|
||||
if (!str.contains(match)) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string does not contain expected millis: "
|
||||
+ "\n\texpected match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
System.out.println("Found expected match for '"+match+"' in \n"+str);
|
||||
|
||||
match = "<nanos>";
|
||||
if (str.contains(match) != useInstant) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string "
|
||||
+ (useInstant
|
||||
? "does not contain expected nanos: "
|
||||
: "contains unexpected nanos: ")
|
||||
+ "\n\t" + (useInstant ? "expected" : "unexpected")
|
||||
+ " match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
match = "<nanos>"+getNanoAdjustment(record)+"</nanos>";
|
||||
if (str.contains(match) != useInstant) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string "
|
||||
+ (useInstant
|
||||
? "does not contain expected nanos: "
|
||||
: "contains unexpected nanos: ")
|
||||
+ "\n\t" + (useInstant ? "expected" : "unexpected")
|
||||
+ " match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
if (useInstant) {
|
||||
System.out.println("Found expected match for '"+match+"' in \n"+str);
|
||||
} else {
|
||||
System.out.println("As expected '"+match+"' is not present in \n"+str);
|
||||
}
|
||||
|
||||
match = useInstant ? DateTimeFormatter.ISO_INSTANT.format(instant)
|
||||
: zdt.truncatedTo(ChronoUnit.SECONDS)
|
||||
.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||
match = "<date>"+match+"</date>";
|
||||
if (!str.contains(match)) {
|
||||
throw new RuntimeException(formatter.getClass().getSimpleName()
|
||||
+ ".format()"
|
||||
+ " string does not contain expected date: "
|
||||
+ "\n\texpected match for: '" + match + "'"
|
||||
+ "\n\tin: \n" + str);
|
||||
}
|
||||
System.out.println("Found expected match for '"+match+"' in \n"+str);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue