49
49
import static com .oracle .svm .jvmtiagentbase .jvmti .JvmtiEvent .JVMTI_EVENT_NATIVE_METHOD_BIND ;
50
50
import static org .graalvm .word .WordFactory .nullPointer ;
51
51
52
+ import java .lang .reflect .Field ;
52
53
import java .nio .ByteBuffer ;
53
54
import java .nio .ByteOrder ;
54
55
import java .util .ArrayList ;
80
81
import com .oracle .svm .agent .stackaccess .EagerlyLoadedJavaStackAccess ;
81
82
import com .oracle .svm .agent .stackaccess .InterceptedState ;
82
83
import com .oracle .svm .agent .tracing .core .Tracer ;
84
+ import com .oracle .svm .configure .ClassNameSupport ;
83
85
import com .oracle .svm .configure .LambdaConfigurationTypeDescriptor ;
84
86
import com .oracle .svm .configure .NamedConfigurationTypeDescriptor ;
85
87
import com .oracle .svm .configure .ProxyConfigurationTypeDescriptor ;
@@ -263,8 +265,17 @@ static Object getTypeDescriptor(JNIEnvironment env, JNIObjectHandle clazz) {
263
265
}
264
266
265
267
private static boolean forName (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
266
- JNIObjectHandle callerClass = state .getDirectCallerClass ();
267
268
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 ();
268
279
String className = fromJniString (jni , name );
269
280
if (className == null ) {
270
281
return true ; /* No point in tracing this. */
@@ -273,6 +284,14 @@ private static boolean forName(JNIEnvironment jni, JNIObjectHandle thread, Break
273
284
return true ;
274
285
}
275
286
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
+
276
295
private static boolean getFields (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
277
296
return handleGetFields (jni , thread , bp , state );
278
297
}
@@ -543,6 +562,34 @@ private static boolean getEnclosingMethod(JNIEnvironment jni, JNIObjectHandle th
543
562
return true ;
544
563
}
545
564
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
+
546
593
private static boolean invokeMethod (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
547
594
return handleInvokeMethod (jni , thread , bp , state , true );
548
595
}
@@ -582,6 +629,27 @@ private static boolean handleInvokeMethod(JNIEnvironment jni, JNIObjectHandle th
582
629
JNIObjectHandle clazz = getObjectArgument (thread , 1 );
583
630
traceReflectBreakpoint (jni , clazz , nullHandle (), callerClass , "newInstance" , clazz .notEqual (nullHandle ()), state .getFullStackTraceOrNull ());
584
631
}
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
+ }
585
653
return true ;
586
654
}
587
655
@@ -597,6 +665,24 @@ private static boolean isClassNewInstance(JNIEnvironment jni, JNIObjectHandle de
597
665
return "java.lang.Class" .equals (className );
598
666
}
599
667
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
+
600
686
private static boolean invokeConstructor (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
601
687
return handleInvokeConstructor (jni , bp , state , getReceiver (thread ));
602
688
}
@@ -1650,6 +1736,7 @@ private interface BreakpointHandler {
1650
1736
private static final BreakpointSpecification [] BREAKPOINT_SPECIFICATIONS = {
1651
1737
brk ("java/lang/Class" , "forName" , "(Ljava/lang/String;)Ljava/lang/Class;" , BreakpointInterceptor ::forName ),
1652
1738
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 ),
1653
1740
1654
1741
brk ("java/lang/Class" , "getFields" , "()[Ljava/lang/reflect/Field;" , BreakpointInterceptor ::getFields ),
1655
1742
brk ("java/lang/Class" , "getClasses" , "()[Ljava/lang/Class;" , BreakpointInterceptor ::getClasses ),
@@ -1673,6 +1760,7 @@ private interface BreakpointHandler {
1673
1760
brk ("java/lang/Class" , "getDeclaredConstructor" , "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;" , BreakpointInterceptor ::getConstructor ),
1674
1761
1675
1762
brk ("java/lang/Class" , "newInstance" , "()Ljava/lang/Object;" , BreakpointInterceptor ::newInstance ),
1763
+ brk ("java/lang/Class" , "arrayType" , "()Ljava/lang/Class;" , BreakpointInterceptor ::arrayType ),
1676
1764
brk ("java/lang/reflect/Array" , "newInstance" , "(Ljava/lang/Class;I)Ljava/lang/Object;" , BreakpointInterceptor ::newArrayInstance ),
1677
1765
brk ("java/lang/reflect/Array" , "newInstance" , "(Ljava/lang/Class;[I)Ljava/lang/Object;" , BreakpointInterceptor ::newArrayInstanceMulti ),
1678
1766
@@ -1712,6 +1800,7 @@ private interface BreakpointHandler {
1712
1800
optionalBrk ("jdk/internal/misc/Unsafe" , "objectFieldOffset" , "(Ljava/lang/Class;Ljava/lang/String;)J" , BreakpointInterceptor ::objectFieldOffsetByName ),
1713
1801
1714
1802
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 ),
1715
1804
1716
1805
optionalBrk ("java/lang/invoke/MethodHandles$Lookup" , "findStatic" ,
1717
1806
"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;" ,
@@ -1762,6 +1851,9 @@ private interface BreakpointHandler {
1762
1851
optionalBrk ("java/lang/invoke/MethodHandles$Lookup" , "unreflectSetter" ,
1763
1852
"(Ljava/lang/reflect/Field;)Ljava/lang/invoke/MethodHandle;" ,
1764
1853
BreakpointInterceptor ::unreflectField ),
1854
+ optionalBrk ("java/lang/invoke/MethodHandles$Lookup" , "unreflectVarHandle" ,
1855
+ "(Ljava/lang/reflect/Field;)Ljava/lang/invoke/VarHandle;" ,
1856
+ BreakpointInterceptor ::unreflectField ),
1765
1857
optionalBrk ("java/lang/invoke/MethodHandleProxies" , "asInterfaceInstance" ,
1766
1858
"(Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;" ,
1767
1859
BreakpointInterceptor ::asInterfaceInstance ),
@@ -1810,6 +1902,24 @@ private static boolean allocateInstance(JNIEnvironment jni, JNIObjectHandle thre
1810
1902
brk ("java/lang/reflect/Method" , "invoke" , "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" , BreakpointInterceptor ::invokeMethod ),
1811
1903
brk ("sun/reflect/misc/MethodUtil" , "invoke" , "(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" , BreakpointInterceptor ::invokeMethod ),
1812
1904
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 ),
1813
1923
};
1814
1924
1815
1925
private static final BreakpointSpecification [] CLASS_PREDEFINITION_BREAKPOINT_SPECIFICATIONS = {
0 commit comments