Skip to content

Commit 888a3f5

Browse files
Automatic merge of master into galahad
2 parents 261e988 + 01f68fc commit 888a3f5

File tree

8 files changed

+230
-110
lines changed

8 files changed

+230
-110
lines changed

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import static com.oracle.svm.jvmtiagentbase.jvmti.JvmtiEvent.JVMTI_EVENT_NATIVE_METHOD_BIND;
5050
import static org.graalvm.word.WordFactory.nullPointer;
5151

52+
import java.lang.reflect.Field;
5253
import java.nio.ByteBuffer;
5354
import java.nio.ByteOrder;
5455
import java.util.ArrayList;
@@ -80,6 +81,7 @@
8081
import com.oracle.svm.agent.stackaccess.EagerlyLoadedJavaStackAccess;
8182
import com.oracle.svm.agent.stackaccess.InterceptedState;
8283
import com.oracle.svm.agent.tracing.core.Tracer;
84+
import com.oracle.svm.configure.ClassNameSupport;
8385
import com.oracle.svm.configure.LambdaConfigurationTypeDescriptor;
8486
import com.oracle.svm.configure.NamedConfigurationTypeDescriptor;
8587
import com.oracle.svm.configure.ProxyConfigurationTypeDescriptor;
@@ -263,8 +265,17 @@ static Object getTypeDescriptor(JNIEnvironment env, JNIObjectHandle clazz) {
263265
}
264266

265267
private static boolean forName(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
266-
JNIObjectHandle callerClass = state.getDirectCallerClass();
267268
JNIObjectHandle name = getObjectArgument(thread, 0);
269+
return handleForName(jni, bp, state, name);
270+
}
271+
272+
private static boolean forNameWithModule(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
273+
JNIObjectHandle name = getObjectArgument(thread, 1);
274+
return handleForName(jni, bp, state, name);
275+
}
276+
277+
private static boolean handleForName(JNIEnvironment jni, Breakpoint bp, InterceptedState state, JNIObjectHandle name) {
278+
JNIObjectHandle callerClass = state.getDirectCallerClass();
268279
String className = fromJniString(jni, name);
269280
if (className == null) {
270281
return true; /* No point in tracing this. */
@@ -273,6 +284,14 @@ private static boolean forName(JNIEnvironment jni, JNIObjectHandle thread, Break
273284
return true;
274285
}
275286

287+
private static boolean arrayType(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
288+
JNIObjectHandle callerClass = state.getDirectCallerClass();
289+
JNIObjectHandle componentType = getReceiver(thread);
290+
String arrayTypeName = ClassNameSupport.getArrayReflectionName(getClassNameOrNull(jni, componentType));
291+
traceReflectBreakpoint(jni, bp.clazz, nullHandle(), callerClass, "forName", null, state.getFullStackTraceOrNull(), arrayTypeName);
292+
return true;
293+
}
294+
276295
private static boolean getFields(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
277296
return handleGetFields(jni, thread, bp, state);
278297
}
@@ -543,6 +562,34 @@ private static boolean getEnclosingMethod(JNIEnvironment jni, JNIObjectHandle th
543562
return true;
544563
}
545564

565+
private static boolean accessField(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
566+
JNIObjectHandle field = getReceiver(thread);
567+
return accessFieldInternal(jni, state, field);
568+
}
569+
570+
private static boolean accessFieldUnsafe(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
571+
JNIObjectHandle field = getObjectArgument(thread, 1);
572+
return accessFieldInternal(jni, state, field);
573+
}
574+
575+
private static boolean accessFieldInternal(JNIEnvironment jni, InterceptedState state, JNIObjectHandle field) {
576+
JNIObjectHandle callerClass = state.getDirectCallerClass();
577+
578+
JNIObjectHandle declaring = Support.callObjectMethod(jni, field, agent.handles().javaLangReflectMemberGetDeclaringClass);
579+
if (clearException(jni)) {
580+
declaring = nullHandle();
581+
}
582+
583+
JNIObjectHandle nameHandle = Support.callObjectMethod(jni, field, agent.handles().javaLangReflectMemberGetName);
584+
if (clearException(jni)) {
585+
nameHandle = nullHandle();
586+
}
587+
String name = fromJniString(jni, nameHandle);
588+
589+
traceReflectBreakpoint(jni, declaring, declaring, callerClass, "accessField", declaring.notEqual(nullHandle()), state.getFullStackTraceOrNull(), name);
590+
return true;
591+
}
592+
546593
private static boolean invokeMethod(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
547594
return handleInvokeMethod(jni, thread, bp, state, true);
548595
}
@@ -582,6 +629,27 @@ private static boolean handleInvokeMethod(JNIEnvironment jni, JNIObjectHandle th
582629
JNIObjectHandle clazz = getObjectArgument(thread, 1);
583630
traceReflectBreakpoint(jni, clazz, nullHandle(), callerClass, "newInstance", clazz.notEqual(nullHandle()), state.getFullStackTraceOrNull());
584631
}
632+
633+
/*
634+
* Calling Field.get/set and associated methods through Method.invoke should register the
635+
* field for reflective access
636+
*/
637+
if (isInvoke && isFieldAccess(jni, declaring, name)) {
638+
JNIObjectHandle field = getObjectArgument(thread, 1);
639+
640+
JNIObjectHandle clazz = Support.callObjectMethod(jni, field, agent.handles().javaLangReflectMemberGetDeclaringClass);
641+
if (clearException(jni)) {
642+
clazz = nullHandle();
643+
}
644+
645+
JNIObjectHandle fieldNameHandle = Support.callObjectMethod(jni, field, agent.handles().javaLangReflectMemberGetName);
646+
if (clearException(jni)) {
647+
clazz = nullHandle();
648+
}
649+
String fieldName = fromJniString(jni, fieldNameHandle);
650+
651+
traceReflectBreakpoint(jni, clazz, nullHandle(), callerClass, "accessField", clazz.notEqual(nullHandle()), state.getFullStackTraceOrNull(), fieldName);
652+
}
585653
return true;
586654
}
587655

@@ -597,6 +665,24 @@ private static boolean isClassNewInstance(JNIEnvironment jni, JNIObjectHandle de
597665
return "java.lang.Class".equals(className);
598666
}
599667

668+
/**
669+
* A call is a field access iff it is a call to a method from {@link Field} whose name starts
670+
* with "get" or "set".
671+
*/
672+
private static boolean isFieldAccess(JNIEnvironment jni, JNIObjectHandle declaring, String name) {
673+
if (declaring.equal(nullHandle()) || name == null || (!name.startsWith("get") && !name.startsWith("set"))) {
674+
return false;
675+
}
676+
677+
JNIObjectHandle classNameHandle = Support.callObjectMethod(jni, declaring, agent.handles().javaLangClassGetName);
678+
if (clearException(jni)) {
679+
classNameHandle = nullHandle();
680+
}
681+
String className = fromJniString(jni, classNameHandle);
682+
683+
return Field.class.getName().equals(className);
684+
}
685+
600686
private static boolean invokeConstructor(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
601687
return handleInvokeConstructor(jni, bp, state, getReceiver(thread));
602688
}
@@ -1650,6 +1736,7 @@ private interface BreakpointHandler {
16501736
private static final BreakpointSpecification[] BREAKPOINT_SPECIFICATIONS = {
16511737
brk("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", BreakpointInterceptor::forName),
16521738
brk("java/lang/Class", "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", BreakpointInterceptor::forName),
1739+
brk("java/lang/Class", "forName", "(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;", BreakpointInterceptor::forNameWithModule),
16531740

16541741
brk("java/lang/Class", "getFields", "()[Ljava/lang/reflect/Field;", BreakpointInterceptor::getFields),
16551742
brk("java/lang/Class", "getClasses", "()[Ljava/lang/Class;", BreakpointInterceptor::getClasses),
@@ -1673,6 +1760,7 @@ private interface BreakpointHandler {
16731760
brk("java/lang/Class", "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getConstructor),
16741761

16751762
brk("java/lang/Class", "newInstance", "()Ljava/lang/Object;", BreakpointInterceptor::newInstance),
1763+
brk("java/lang/Class", "arrayType", "()Ljava/lang/Class;", BreakpointInterceptor::arrayType),
16761764
brk("java/lang/reflect/Array", "newInstance", "(Ljava/lang/Class;I)Ljava/lang/Object;", BreakpointInterceptor::newArrayInstance),
16771765
brk("java/lang/reflect/Array", "newInstance", "(Ljava/lang/Class;[I)Ljava/lang/Object;", BreakpointInterceptor::newArrayInstanceMulti),
16781766

@@ -1712,6 +1800,7 @@ private interface BreakpointHandler {
17121800
optionalBrk("jdk/internal/misc/Unsafe", "objectFieldOffset", "(Ljava/lang/Class;Ljava/lang/String;)J", BreakpointInterceptor::objectFieldOffsetByName),
17131801

17141802
brk("sun/misc/Unsafe", "allocateInstance", "(Ljava/lang/Class;)Ljava/lang/Object;", BreakpointInterceptor::allocateInstance),
1803+
brk("sun/misc/Unsafe", "objectFieldOffset", "(Ljava/lang/reflect/Field;)J", BreakpointInterceptor::accessFieldUnsafe),
17151804

17161805
optionalBrk("java/lang/invoke/MethodHandles$Lookup", "findStatic",
17171806
"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;",
@@ -1762,6 +1851,9 @@ private interface BreakpointHandler {
17621851
optionalBrk("java/lang/invoke/MethodHandles$Lookup", "unreflectSetter",
17631852
"(Ljava/lang/reflect/Field;)Ljava/lang/invoke/MethodHandle;",
17641853
BreakpointInterceptor::unreflectField),
1854+
optionalBrk("java/lang/invoke/MethodHandles$Lookup", "unreflectVarHandle",
1855+
"(Ljava/lang/reflect/Field;)Ljava/lang/invoke/VarHandle;",
1856+
BreakpointInterceptor::unreflectField),
17651857
optionalBrk("java/lang/invoke/MethodHandleProxies", "asInterfaceInstance",
17661858
"(Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;",
17671859
BreakpointInterceptor::asInterfaceInstance),
@@ -1810,6 +1902,24 @@ private static boolean allocateInstance(JNIEnvironment jni, JNIObjectHandle thre
18101902
brk("java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", BreakpointInterceptor::invokeMethod),
18111903
brk("sun/reflect/misc/MethodUtil", "invoke", "(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", BreakpointInterceptor::invokeMethod),
18121904
brk("java/lang/reflect/Constructor", "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;", BreakpointInterceptor::invokeConstructor),
1905+
brk("java/lang/reflect/Field", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", BreakpointInterceptor::accessField),
1906+
brk("java/lang/reflect/Field", "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", BreakpointInterceptor::accessField),
1907+
brk("java/lang/reflect/Field", "getBoolean", "(Ljava/lang/Object;)Z", BreakpointInterceptor::accessField),
1908+
brk("java/lang/reflect/Field", "setBoolean", "(Ljava/lang/Object;Z)V", BreakpointInterceptor::accessField),
1909+
brk("java/lang/reflect/Field", "getByte", "(Ljava/lang/Object;)B", BreakpointInterceptor::accessField),
1910+
brk("java/lang/reflect/Field", "setByte", "(Ljava/lang/Object;B)V", BreakpointInterceptor::accessField),
1911+
brk("java/lang/reflect/Field", "getShort", "(Ljava/lang/Object;)S", BreakpointInterceptor::accessField),
1912+
brk("java/lang/reflect/Field", "setShort", "(Ljava/lang/Object;S)V", BreakpointInterceptor::accessField),
1913+
brk("java/lang/reflect/Field", "getChar", "(Ljava/lang/Object;)C", BreakpointInterceptor::accessField),
1914+
brk("java/lang/reflect/Field", "setChar", "(Ljava/lang/Object;C)V", BreakpointInterceptor::accessField),
1915+
brk("java/lang/reflect/Field", "getInt", "(Ljava/lang/Object;)I", BreakpointInterceptor::accessField),
1916+
brk("java/lang/reflect/Field", "setInt", "(Ljava/lang/Object;I)V", BreakpointInterceptor::accessField),
1917+
brk("java/lang/reflect/Field", "getLong", "(Ljava/lang/Object;)J", BreakpointInterceptor::accessField),
1918+
brk("java/lang/reflect/Field", "setLong", "(Ljava/lang/Object;J)V", BreakpointInterceptor::accessField),
1919+
brk("java/lang/reflect/Field", "getFloat", "(Ljava/lang/Object;)F", BreakpointInterceptor::accessField),
1920+
brk("java/lang/reflect/Field", "setFloat", "(Ljava/lang/Object;F)V", BreakpointInterceptor::accessField),
1921+
brk("java/lang/reflect/Field", "getDouble", "(Ljava/lang/Object;)D", BreakpointInterceptor::accessField),
1922+
brk("java/lang/reflect/Field", "setDouble", "(Ljava/lang/Object;D)V", BreakpointInterceptor::accessField),
18131923
};
18141924

18151925
private static final BreakpointSpecification[] CLASS_PREDEFINITION_BREAKPOINT_SPECIFICATIONS = {

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ClassNameSupport.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@ private static String reflectionNameToJNINameUnchecked(String reflectionName) {
124124
return reflectionName.replace('.', '/');
125125
}
126126

127+
public static String getArrayReflectionName(String componentReflectionName) {
128+
if (!isValidReflectionName(componentReflectionName)) {
129+
return componentReflectionName;
130+
}
131+
return "[" + (wrappingArrayDimension(componentReflectionName) > 0 ? componentReflectionName : typeNameToArrayElementType(componentReflectionName));
132+
}
133+
127134
private static String arrayElementTypeToTypeName(String arrayElementType, int startIndex) {
128135
char typeChar = arrayElementType.charAt(startIndex);
129136
return switch (typeChar) {

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/AccessAdvisor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ public final class AccessAdvisor {
113113
// BytecodeDescriptor calls Class.forName
114114
internalCallerFilter.addOrGetChildren("sun.invoke.util.BytecodeDescriptor", ConfigurationFilter.Inclusion.Include);
115115
internalCallerFilter.addOrGetChildren("sun.launcher.**", ConfigurationFilter.Inclusion.Exclude);
116+
// LoggingMXBeanAccess calls Class.forName
117+
internalCallerFilter.addOrGetChildren("sun.management.ManagementFactoryHelper$LoggingMXBeanAccess", ConfigurationFilter.Inclusion.Exclude);
116118
internalCallerFilter.addOrGetChildren("sun.misc.**", ConfigurationFilter.Inclusion.Exclude);
117119
internalCallerFilter.addOrGetChildren("sun.net.**", ConfigurationFilter.Inclusion.Exclude);
118120
// Uses constructor reflection on exceptions

0 commit comments

Comments
 (0)