8261160: Add a deserialization JFR event

Co-authored-by: Sean Coffey <coffeys@openjdk.org>
Co-authored-by: Chris Hegarty <chegar@openjdk.org>
Reviewed-by: coffeys, rriggs, dfuchs, egahlin
This commit is contained in:
Chris Hegarty 2021-02-12 17:35:25 +00:00
parent a305743cfa
commit 3dc6f52a89
12 changed files with 615 additions and 22 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -48,6 +48,7 @@ import java.util.concurrent.ConcurrentMap;
import static java.io.ObjectStreamClass.processQueue;
import jdk.internal.access.SharedSecrets;
import jdk.internal.event.DeserializationEvent;
import jdk.internal.misc.Unsafe;
import sun.reflect.misc.ReflectUtil;
import sun.security.action.GetBooleanAction;
@ -1323,9 +1324,12 @@ public class ObjectInputStream
}
/**
* Invoke the serialization filter if non-null.
* Invokes the serialization filter if non-null.
*
* If the filter rejects or an exception is thrown, throws InvalidClassException.
*
* Logs and/or commits a {@code DeserializationEvent}, if configured.
*
* @param clazz the class; may be null
* @param arrayLength the array length requested; use {@code -1} if not creating an array
* @throws InvalidClassException if it rejected by the filter or
@ -1333,11 +1337,12 @@ public class ObjectInputStream
*/
private void filterCheck(Class<?> clazz, int arrayLength)
throws InvalidClassException {
// Info about the stream is not available if overridden by subclass, return 0
long bytesRead = (bin == null) ? 0 : bin.getBytesRead();
RuntimeException ex = null;
ObjectInputFilter.Status status = null;
if (serialFilter != null) {
RuntimeException ex = null;
ObjectInputFilter.Status status;
// Info about the stream is not available if overridden by subclass, return 0
long bytesRead = (bin == null) ? 0 : bin.getBytesRead();
try {
status = serialFilter.checkInput(new FilterValues(clazz, arrayLength,
totalObjectRefs, depth, bytesRead));
@ -1355,12 +1360,24 @@ public class ObjectInputStream
status, clazz, arrayLength, totalObjectRefs, depth, bytesRead,
Objects.toString(ex, "n/a"));
}
if (status == null ||
status == ObjectInputFilter.Status.REJECTED) {
InvalidClassException ice = new InvalidClassException("filter status: " + status);
ice.initCause(ex);
throw ice;
}
}
DeserializationEvent event = new DeserializationEvent();
if (event.shouldCommit()) {
event.filterConfigured = serialFilter != null;
event.filterStatus = status != null ? status.name() : null;
event.type = clazz;
event.arrayLength = arrayLength;
event.objectReferences = totalObjectRefs;
event.depth = depth;
event.bytesRead = bytesRead;
event.exceptionType = ex != null ? ex.getClass() : null;
event.exceptionMessage = ex != null ? ex.getMessage() : null;
event.commit();
}
if (serialFilter != null && (status == null || status == ObjectInputFilter.Status.REJECTED)) {
InvalidClassException ice = new InvalidClassException("filter status: " + status);
ice.initCause(ex);
throw ice;
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package jdk.internal.event;
/**
* Event details relating to deserialization.
*/
public final class DeserializationEvent extends Event {
public boolean filterConfigured;
public String filterStatus;
public Class<?> type;
public int arrayLength;
public long objectReferences;
public long depth;
public long bytesRead;
public Class<?> exceptionType;
public String exceptionMessage;
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package jdk.jfr.events;
import jdk.jfr.Category;
import jdk.jfr.Description;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.internal.MirrorEvent;
@Category({"Java Development Kit", "Serialization"})
@Label("Deserialization")
@Name("jdk.Deserialization")
@Description("Results of deserialiation and ObjectInputFilter checks")
@MirrorEvent(className = "jdk.internal.event.DeserializationEvent")
public final class DeserializationEvent extends AbstractJDKEvent {
@Label("Filter Configured")
public boolean filterConfigured;
@Label("Filter Status")
public String filterStatus;
@Label ("Type")
public Class<?> type;
@Label ("Array Length")
public int arrayLength;
@Label ("Object References")
public long objectReferences;
@Label ("Depth")
public long depth;
@Label ("Bytes Read")
public long bytesRead;
@Label ("Exception Type")
public Class<?> exceptionType;
@Label ("Exception Message")
public String exceptionMessage;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,6 +38,7 @@ import jdk.jfr.events.ExceptionThrownEvent;
import jdk.jfr.events.FileForceEvent;
import jdk.jfr.events.FileReadEvent;
import jdk.jfr.events.FileWriteEvent;
import jdk.jfr.events.DeserializationEvent;
import jdk.jfr.events.ProcessStartEvent;
import jdk.jfr.events.SecurityPropertyModificationEvent;
import jdk.jfr.events.SocketReadEvent;
@ -55,11 +56,12 @@ import jdk.jfr.internal.SecuritySupport;
public final class JDKEvents {
private static final Class<?>[] mirrorEventClasses = {
DeserializationEvent.class,
ProcessStartEvent.class,
SecurityPropertyModificationEvent.class,
TLSHandshakeEvent.class,
X509CertificateEvent.class,
X509ValidationEvent.class,
ProcessStartEvent.class
X509ValidationEvent.class
};
private static final Class<?>[] eventClasses = {
@ -73,11 +75,13 @@ public final class JDKEvents {
ErrorThrownEvent.class,
ActiveSettingEvent.class,
ActiveRecordingEvent.class,
jdk.internal.event.DeserializationEvent.class,
jdk.internal.event.ProcessStartEvent.class,
jdk.internal.event.SecurityPropertyModificationEvent.class,
jdk.internal.event.TLSHandshakeEvent.class,
jdk.internal.event.X509CertificateEvent.class,
jdk.internal.event.X509ValidationEvent.class,
jdk.internal.event.ProcessStartEvent.class,
DirectBufferStatisticsEvent.class
};

View File

@ -665,6 +665,11 @@
<setting name="threshold" control="socket-io-threshold">20 ms</setting>
</event>
<event name="jdk.Deserialization">
<setting name="enabled">false</setting>
<setting name="stackTrace">true</setting>
</event>
<event name="jdk.SecurityPropertyModification">
<setting name="enabled">false</setting>
<setting name="stackTrace">true</setting>

View File

@ -665,6 +665,11 @@
<setting name="threshold" control="socket-io-threshold">10 ms</setting>
</event>
<event name="jdk.Deserialization">
<setting name="enabled">false</setting>
<setting name="stackTrace">true</setting>
</event>
<event name="jdk.SecurityPropertyModification">
<setting name="enabled">false</setting>
<setting name="stackTrace">true</setting>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -53,6 +53,18 @@ import org.testng.annotations.DataProvider;
*
* @summary Test Global Filters
*/
/* @test
* @bug 8261160
* @summary Add a deserialization JFR event
* @build GlobalFilterTest SerialFilterTest
* @requires vm.hasJFR
* @run testng/othervm/policy=security.policy
* -XX:StartFlightRecording=name=DeserializationEvent,dumponexit=true
* -Djava.security.properties=${test.src}/java.security-extra1
* -Djava.security.debug=properties GlobalFilterTest
*/
@Test
public class GlobalFilterTest {
private static final String serialPropName = "jdk.serialFilter";

View File

@ -0,0 +1,437 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
package jdk.jfr.event.io;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectInputFilter.Status;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import jdk.jfr.Recording;
import jdk.jfr.consumer.RecordedClass;
import jdk.jfr.consumer.RecordedEvent;
import jdk.test.lib.jfr.EventNames;
import jdk.test.lib.jfr.Events;
import jdk.test.lib.serial.SerialObjectBuilder;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.System.out;
import static org.testng.Assert.*;
/*
* @test
* @bug 8261160
* @summary Add a deserialization JFR event
* @key jfr
* @requires vm.hasJFR
* @library /test/lib
* @run testng/othervm jdk.jfr.event.io.TestDeserializationEvent
*/
public class TestDeserializationEvent {
public record R() implements Serializable { }
@DataProvider(name = "scenarios")
public Object[][] scenarios() throws Exception {
byte[] ba1 = serialize(new R());
byte[] ba2 = serialize(new int[] { 56, 67, 58, 59, 60 });
byte[] ba3 = serialize(new R[] { new R(), new R() });
byte[] ba4 = serialize(new char[][] { new char[] {'a', 'b'}, new char[] {'c'} });
// data provider columns- 1:id, 2:deserialize-operation, 3:expected-event-checkers
return new Object[][] {
{ 1, // single stream object, R
(Runnable)() -> deserialize(ba1),
List.of(
Set.of(
assertFilterStatus(null),
assertType(R.class),
assertArrayLength(-1),
assertObjectReferences(1),
assertDepth(1),
assertHasBytesRead(),
assertExceptionType(null),
assertExceptionMessage(null))) },
{ 2, // primitive int array
(Runnable)() -> deserialize(ba2),
List.of(
Set.of( // TC_CLASS, for array class int[]
assertType(int[].class),
assertArrayLength(-1)),
Set.of( // TC_ARRAY, actual array
assertType(int[].class),
assertArrayLength(5))) },
{ 3, // reference array, R
(Runnable)() -> deserialize(ba3),
List.of(
Set.of( // TC_CLASS, for array class R[]
assertType(R[].class),
assertArrayLength(-1)),
Set.of( // TC_ARRAY, actual array
assertType(R[].class),
assertArrayLength(2)),
Set.of( // TC_CLASS, for R
assertType(R.class),
assertArrayLength(-1)),
Set.of( // TC_REFERENCE, for TC_CLASS relating second stream obj
assertType(null),
assertArrayLength(-1))) },
{ 4, // multi-dimensional prim char array
(Runnable)() -> deserialize(ba4),
List.of(
Set.of( // TC_CLASS, for array class char[][]
assertType(char[][].class),
assertArrayLength(-1),
assertDepth(1)),
Set.of( // TC_ARRAY, actual char[][] array
assertType(char[][].class),
assertArrayLength(2),
assertDepth(1)),
Set.of( // TC_CLASS, for array class char[]
assertType(char[].class),
assertArrayLength(-1),
assertDepth(2)),
Set.of( // TC_ARRAY, first char[] array
assertType(char[].class),
assertArrayLength(2),
assertDepth(2)),
Set.of( // TC_REFERENCE, for TC_CLASS relating to second stream array
assertType(null),
assertArrayLength(-1),
assertDepth(2)),
Set.of( // TC_ARRAY, second char[] array
assertType(char[].class),
assertArrayLength(1),
assertDepth(2))) }
};
}
@Test(dataProvider = "scenarios")
public void test(int id,
Runnable thunk,
List<Set<Consumer<RecordedEvent>>> expectedValuesChecker)
throws IOException
{
try (Recording recording = new Recording()) {
recording.enable(EventNames.Deserialization);
recording.start();
thunk.run();
recording.stop();
List<RecordedEvent> events = Events.fromRecording(recording);
assertEquals(events.size(), expectedValuesChecker.size());
assertEventList(events, expectedValuesChecker);
}
}
static final Class<InvalidClassException> ICE = InvalidClassException.class;
@DataProvider(name = "filterDisallowedValues")
public Object[][] filterDisallowedValues() {
return new Object[][] {
{ Status.REJECTED, "REJECTED" },
{ null, null }
};
}
@Test(dataProvider = "filterDisallowedValues")
public void testFilterDisallow(Status filterStatus,
String expectedValue)
throws Exception
{
try (Recording recording = new Recording();
var bais = new ByteArrayInputStream(serialize(new R()));
var ois = new ObjectInputStream(bais)) {
ois.setObjectInputFilter(fv -> filterStatus);
recording.enable(EventNames.Deserialization);
recording.start();
assertThrows(ICE, () -> ois.readObject());
recording.stop();
List<RecordedEvent> events = Events.fromRecording(recording);
assertEquals(events.size(), 1);
assertEquals(events.get(0).getEventType().getName(), "jdk.Deserialization");
assertFilterConfigured(true).accept(events.get(0));
assertFilterStatus(expectedValue).accept(events.get(0));
}
}
@DataProvider(name = "filterAllowedValues")
public Object[][] filterAllowedValues() {
return new Object[][] {
{ Status.ALLOWED, "ALLOWED" },
{ Status.UNDECIDED, "UNDECIDED" },
};
}
@Test(dataProvider = "filterAllowedValues")
public void testFilterAllowed(Status filterStatus,
String expectedValue) throws Exception {
try (Recording recording = new Recording();
var bais = new ByteArrayInputStream(serialize(new R()));
var ois = new ObjectInputStream(bais)) {
ois.setObjectInputFilter(fv -> filterStatus);
recording.enable(EventNames.Deserialization);
recording.start();
ois.readObject();
recording.stop();
List<RecordedEvent> events = Events.fromRecording(recording);
assertEquals(events.size(), 1);
assertEquals(events.get(0).getEventType().getName(), "jdk.Deserialization");
assertFilterConfigured(true).accept(events.get(0));
assertFilterStatus(expectedValue).accept(events.get(0));
}
}
static class XYZException extends RuntimeException {
XYZException(String msg) { super(msg); }
}
@Test
public void testException() throws Exception {
try (Recording recording = new Recording();
var bais = new ByteArrayInputStream(serialize(new R()));
var ois = new ObjectInputStream(bais)) {
ois.setObjectInputFilter(fv -> { throw new XYZException("I am a bad filter!!!"); });
recording.enable(EventNames.Deserialization);
recording.start();
assertThrows(ICE, () -> ois.readObject());
recording.stop();
List<RecordedEvent> events = Events.fromRecording(recording);
assertEquals(events.size(), 1);
assertEquals(events.get(0).getEventType().getName(), "jdk.Deserialization");
assertFilterConfigured(true).accept(events.get(0));
assertExceptionType(XYZException.class).accept(events.get(0));
assertExceptionMessage("I am a bad filter!!!").accept(events.get(0));
}
}
static void assertEventList(List<RecordedEvent> actualEvents,
List<Set<Consumer<RecordedEvent>>> expectedValuesChecker) {
int found = 0;
for (RecordedEvent recordedEvent : actualEvents) {
assertEquals(recordedEvent.getEventType().getName(), "jdk.Deserialization");
out.println("Checking recorded event:" + recordedEvent);
Set<Consumer<RecordedEvent>> checkers = expectedValuesChecker.get(found);
for (Consumer<RecordedEvent> checker : checkers) {
out.println(" checking:" + checker);
checker.accept(recordedEvent);
}
assertFilterConfigured(false).accept(recordedEvent); // no filter expected
assertExceptionType(null).accept(recordedEvent); // no exception type expected
assertExceptionMessage(null).accept(recordedEvent); // no exception message expected
found++;
}
assertEquals(found, expectedValuesChecker.size());
}
static Consumer<RecordedEvent> assertFilterConfigured(boolean expectedValue) {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertTrue(recordedEvent.hasField("filterConfigured"));
assertEquals((boolean)recordedEvent.getValue("filterConfigured"), expectedValue);
}
@Override public String toString() {
return "assertFilterConfigured, expectedValue=" + expectedValue;
}
};
}
static Consumer<RecordedEvent> assertFilterStatus(String expectedValue) {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertTrue(recordedEvent.hasField("filterStatus"));
assertEquals(recordedEvent.getValue("filterStatus"), expectedValue);
}
@Override public String toString() {
return "assertFilterStatus, expectedValue=" + expectedValue;
}
};
}
static Consumer<RecordedEvent> assertType(Class<?> expectedValue) {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertTrue(recordedEvent.hasField("type"));
assertClassOrNull(expectedValue, recordedEvent, "type");
}
@Override public String toString() {
return "assertType, expectedValue=" + expectedValue;
}
};
}
static Consumer<RecordedEvent> assertArrayLength(int expectedValue) {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertTrue(recordedEvent.hasField("arrayLength"));
assertEquals((int)recordedEvent.getValue("arrayLength"), expectedValue);
}
@Override public String toString() {
return "assertArrayLength, expectedValue=" + expectedValue;
}
};
}
static Consumer<RecordedEvent> assertObjectReferences(long expectedValue) {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertTrue(recordedEvent.hasField("objectReferences"));
assertEquals((long)recordedEvent.getValue("objectReferences"), expectedValue);
}
@Override public String toString() {
return "assertObjectReferences, expectedValue=" + expectedValue;
}
};
}
static Consumer<RecordedEvent> assertDepth(long expectedValue) {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertTrue(recordedEvent.hasField("depth"));
assertEquals((long)recordedEvent.getValue("depth"), expectedValue);
}
@Override public String toString() {
return "assertDepth, expectedValue=" + expectedValue;
}
};
}
static Consumer<RecordedEvent> assertHasBytesRead() {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertTrue(recordedEvent.hasField("bytesRead"));
}
@Override public String toString() {
return "assertHasBytesRead,";
}
};
}
static Consumer<RecordedEvent> assertBytesRead(long expectedValue) {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertHasBytesRead().accept(recordedEvent);
assertEquals((long)recordedEvent.getValue("bytesRead"), expectedValue);
}
@Override public String toString() {
return "assertBytesRead, expectedValue=" + expectedValue;
}
};
}
static Consumer<RecordedEvent> assertExceptionType(Class<?> expectedValue) {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertTrue(recordedEvent.hasField("exceptionType"));
assertClassOrNull(expectedValue, recordedEvent, "exceptionType");
}
@Override public String toString() {
return "assertExceptionType, expectedValue=" + expectedValue;
}
};
}
static Consumer<RecordedEvent> assertExceptionMessage(String expectedValue) {
return new Consumer<>() {
@Override public void accept(RecordedEvent recordedEvent) {
assertTrue(recordedEvent.hasField("exceptionMessage"));
assertEquals(recordedEvent.getValue("exceptionMessage"), expectedValue);
}
@Override public String toString() {
return "assertExceptionMessage, expectedValue=" + expectedValue;
}
};
}
static void assertClassOrNull(Class<?> expectedValue,
RecordedEvent recordedEvent,
String valueName) {
if (expectedValue == null && recordedEvent.getValue(valueName) == null)
return;
if (recordedEvent.getValue(valueName) instanceof RecordedClass recordedClass)
assertEquals(recordedClass.getName(), expectedValue.getName());
else
fail("Expected RecordedClass, got:" + recordedEvent.getValue(valueName).getClass());
}
static <T> byte[] serialize(T obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
@SuppressWarnings("unchecked")
static <T> T deserialize(byte[] streamBytes) {
try {
ByteArrayInputStream bais = new ByteArrayInputStream(streamBytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// ---
static volatile boolean initializedFoo; // false
// Do not inadvertently initialize this class, Foo.
static class Foo implements Serializable {
static { TestDeserializationEvent.initializedFoo = true; }
}
/**
* Checks that the creation and recording of the Deserialization event does
* not inadvertently trigger initialization of the class of the stream
* object, when deserialization is rejected by the filter.
*/
@Test
public void testRejectedClassNotInitialized() throws Exception {
byte[] bytes = SerialObjectBuilder.newBuilder("Foo").build();
assertFalse(initializedFoo); // sanity
try (Recording recording = new Recording();
var bais = new ByteArrayInputStream(bytes);
var ois = new ObjectInputStream(bais)) {
ois.setObjectInputFilter(fv -> Status.REJECTED);
recording.enable(EventNames.Deserialization);
recording.start();
assertThrows(ICE, () -> ois.readObject());
recording.stop();
List<RecordedEvent> events = Events.fromRecording(recording);
assertEquals(events.size(), 1);
assertEquals(events.get(0).getEventType().getName(), "jdk.Deserialization");
assertFilterConfigured(true).accept(events.get(0));
assertFilterStatus("REJECTED").accept(events.get(0));
assertFalse(initializedFoo);
assertType(Foo.class);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -178,6 +178,7 @@ public class TestDefaultConfigurations {
insertSetting(doc, EventNames.X509Certificate, "threshold", "0 ns");
insertSetting(doc, EventNames.X509Validation, "threshold", "0 ns");
insertSetting(doc, EventNames.ProcessStart, "threshold", "0 ns");
insertSetting(doc, EventNames.Deserialization, "threshold", "0 ns");
return doc;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -212,9 +212,9 @@ public class TestEventMetadata {
String lowerCased = name.toLowerCase();
Asserts.assertFalse(lowerCased.contains("info") && !lowerCased.contains("information"), "Use 'information' instead 'info' in name");
Asserts.assertFalse(lowerCased.contains("alloc") && !lowerCased.contains("alloca"), "Use 'allocation' instead 'alloc' in name");
Asserts.assertFalse(lowerCased.contains("config") && !lowerCased.contains("configuration"), "Use 'configuration' instead of 'config' in name");
Asserts.assertFalse(lowerCased.contains("config") && !(lowerCased.contains("configuration") || lowerCased.contains("filterconfigured")), "Use 'configuration' instead of 'config' in name");
Asserts.assertFalse(lowerCased.contains("evac") && !lowerCased.contains("evacu"), "Use 'evacuation' instead of 'evac' in name");
Asserts.assertFalse(lowerCased.contains("stat") && !(lowerCased.contains("state") ||lowerCased.contains("statistic")) , "Use 'statistics' instead of 'stat' in name");
Asserts.assertFalse(lowerCased.contains("stat") && !(lowerCased.contains("state") ||lowerCased.contains("statistic") ||lowerCased.contains("filterstatus")) , "Use 'statistics' instead of 'stat' in name");
Asserts.assertFalse(name.contains("ID") , "Use 'id' or 'Id' instead of 'ID' in name");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -206,6 +206,7 @@ public final class TestActiveSettingEvent {
settingValues.put(EventNames.X509Certificate + "#threshold", "0 ns");
settingValues.put(EventNames.X509Validation + "#threshold", "0 ns");
settingValues.put(EventNames.ProcessStart + "#threshold", "0 ns");
settingValues.put(EventNames.Deserialization + "#threshold", "0 ns");
try (Recording recording = new Recording(c)) {
Map<Long, EventType> eventTypes = new HashMap<>();

View File

@ -199,6 +199,8 @@ public class EventNames {
public final static String X509Validation = PREFIX + "X509Validation";
public final static String SecurityProperty = PREFIX + "SecurityPropertyModification";
public final static String DirectBufferStatistics = PREFIX + "DirectBufferStatistics";
public final static String Deserialization = PREFIX + "Deserialization";
// Flight Recorder
public final static String DumpReason = PREFIX + "DumpReason";