Skip to content

Commit 11f7735

Browse files
committed
Reflection bugfixes for missing registration errors
1 parent 63b91c7 commit 11f7735

File tree

6 files changed

+39
-125
lines changed

6 files changed

+39
-125
lines changed

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

Lines changed: 24 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@
8282
import com.oracle.svm.agent.tracing.core.Tracer;
8383
import com.oracle.svm.configure.trace.AccessAdvisor;
8484
import com.oracle.svm.core.c.function.CEntryPointOptions;
85-
import com.oracle.svm.core.jni.JNIObjectHandles;
8685
import com.oracle.svm.core.jni.headers.JNIEnvironment;
8786
import com.oracle.svm.core.jni.headers.JNIFieldId;
8887
import com.oracle.svm.core.jni.headers.JNIMethodId;
@@ -481,8 +480,7 @@ private static boolean handleInvokeMethod(JNIEnvironment jni, JNIObjectHandle th
481480
*/
482481
if (isInvoke && isClassNewInstance(jni, declaring, name)) {
483482
JNIObjectHandle clazz = getObjectArgument(thread, 1);
484-
JNIMethodId result = newInstanceMethodID(jni, clazz);
485-
traceReflectBreakpoint(jni, clazz, nullHandle(), callerClass, "newInstance", result.notEqual(nullHandle()), state.getFullStackTraceOrNull());
483+
traceReflectBreakpoint(jni, clazz, nullHandle(), callerClass, "newInstance", clazz.notEqual(nullHandle()), state.getFullStackTraceOrNull());
486484
}
487485
return true;
488486
}
@@ -529,26 +527,10 @@ private static boolean handleInvokeConstructor(JNIEnvironment jni, @SuppressWarn
529527
private static boolean newInstance(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
530528
JNIObjectHandle callerClass = state.getDirectCallerClass();
531529
JNIObjectHandle self = getReceiver(thread);
532-
JNIMethodId result = newInstanceMethodID(jni, self);
533-
traceReflectBreakpoint(jni, self, nullHandle(), callerClass, bp.specification.methodName, result.notEqual(nullHandle()), state.getFullStackTraceOrNull());
530+
traceReflectBreakpoint(jni, self, nullHandle(), callerClass, bp.specification.methodName, self.notEqual(nullHandle()), state.getFullStackTraceOrNull());
534531
return true;
535532
}
536533

537-
private static JNIMethodId newInstanceMethodID(JNIEnvironment jni, JNIObjectHandle clazz) {
538-
JNIMethodId result = nullPointer();
539-
String name = "<init>";
540-
String signature = "()V";
541-
if (clazz.notEqual(nullHandle())) {
542-
try (CCharPointerHolder ctorName = toCString(name); CCharPointerHolder ctorSignature = toCString(signature)) {
543-
result = jniFunctions().getGetMethodID().invoke(jni, clazz, ctorName.get(), ctorSignature.get());
544-
}
545-
if (clearException(jni)) {
546-
result = nullPointer();
547-
}
548-
}
549-
return result;
550-
}
551-
552534
private static boolean newArrayInstance(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
553535
JNIValue args = StackValue.get(2, JNIValue.class);
554536
args.addressOf(0).setObject(getObjectArgument(thread, 0));
@@ -799,14 +781,9 @@ private static boolean loadClass(JNIEnvironment jni, JNIObjectHandle thread, Bre
799781
observedExplicitLoadClassCallSites.put(location, Boolean.TRUE);
800782
}
801783
}
802-
JNIObjectHandle self = getReceiver(thread);
803784
JNIObjectHandle name = getObjectArgument(thread, 1);
804785
String className = fromJniString(jni, name);
805-
JNIObjectHandle clazz = Support.callObjectMethodL(jni, self, bp.method, name);
806-
if (clearException(jni)) {
807-
clazz = nullHandle();
808-
}
809-
traceReflectBreakpoint(jni, bp.clazz, nullHandle(), callerClass, bp.specification.methodName, clazz.notEqual(nullHandle()), state.getFullStackTraceOrNull(), className);
786+
traceReflectBreakpoint(jni, bp.clazz, nullHandle(), callerClass, bp.specification.methodName, className != null, state.getFullStackTraceOrNull(), className);
810787
return true;
811788
}
812789

@@ -858,70 +835,53 @@ private static boolean isLoadClassInvocation(JNIObjectHandle clazz, JNIMethodId
858835
}
859836
}
860837

861-
private static boolean findMethodHandle(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
838+
private static boolean findMethodHandle(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
862839
JNIObjectHandle callerClass = state.getDirectCallerClass();
863-
JNIObjectHandle lookup = getReceiver(thread);
864840
JNIObjectHandle declaringClass = getObjectArgument(thread, 1);
865841
JNIObjectHandle methodName = getObjectArgument(thread, 2);
866842
JNIObjectHandle methodType = getObjectArgument(thread, 3);
867843

868-
JNIObjectHandle result = Support.callObjectMethodLLL(jni, lookup, bp.method, declaringClass, methodName, methodType);
869-
result = shouldIncludeMethod(jni, result, agent.handles().javaLangIllegalAccessException);
870-
871-
return methodMethodHandle(jni, declaringClass, callerClass, methodName, getParamTypes(jni, methodType), result, state.getFullStackTraceOrNull());
844+
return methodMethodHandle(jni, declaringClass, callerClass, methodName, getParamTypes(jni, methodType), state.getFullStackTraceOrNull());
872845
}
873846

874-
private static boolean findSpecialHandle(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
847+
private static boolean findSpecialHandle(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
875848
JNIObjectHandle callerClass = state.getDirectCallerClass();
876-
JNIObjectHandle lookup = getReceiver(thread);
877849
JNIObjectHandle declaringClass = getObjectArgument(thread, 1);
878850
JNIObjectHandle methodName = getObjectArgument(thread, 2);
879851
JNIObjectHandle methodType = getObjectArgument(thread, 3);
880-
JNIObjectHandle specialCaller = getObjectArgument(thread, 4);
881852

882-
JNIObjectHandle result = Support.callObjectMethodLLLL(jni, lookup, bp.method, declaringClass, methodName, methodType, specialCaller);
883-
result = shouldIncludeMethod(jni, result, agent.handles().javaLangIllegalAccessException);
884-
885-
return methodMethodHandle(jni, declaringClass, callerClass, methodName, getParamTypes(jni, methodType), result, state.getFullStackTraceOrNull());
853+
return methodMethodHandle(jni, declaringClass, callerClass, methodName, getParamTypes(jni, methodType), state.getFullStackTraceOrNull());
886854
}
887855

888-
private static boolean bindHandle(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
856+
private static boolean bindHandle(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
889857
JNIObjectHandle callerClass = state.getDirectCallerClass();
890-
JNIObjectHandle lookup = getReceiver(thread);
891858
JNIObjectHandle receiver = getObjectArgument(thread, 1);
892859
JNIObjectHandle methodName = getObjectArgument(thread, 2);
893860
JNIObjectHandle methodType = getObjectArgument(thread, 3);
894861

895-
JNIObjectHandle result = Support.callObjectMethodLLL(jni, lookup, bp.method, receiver, methodName, methodType);
896-
result = shouldIncludeMethod(jni, result, agent.handles().javaLangIllegalAccessException);
897-
898862
JNIObjectHandle declaringClass = Support.callObjectMethod(jni, receiver, agent.handles().javaLangObjectGetClass);
899863
if (clearException(jni)) {
900864
declaringClass = nullHandle();
901865
}
902866

903-
return methodMethodHandle(jni, declaringClass, callerClass, methodName, getParamTypes(jni, methodType), result, state.getFullStackTraceOrNull());
867+
return methodMethodHandle(jni, declaringClass, callerClass, methodName, getParamTypes(jni, methodType), state.getFullStackTraceOrNull());
904868
}
905869

906870
private static boolean methodMethodHandle(JNIEnvironment jni, JNIObjectHandle declaringClass, JNIObjectHandle callerClass, JNIObjectHandle nameHandle, JNIObjectHandle paramTypesHandle,
907-
JNIObjectHandle result, JNIMethodId[] stackTrace) {
871+
JNIMethodId[] stackTrace) {
908872
String name = fromJniString(jni, nameHandle);
909873
Object paramTypes = getClassArrayNames(jni, paramTypesHandle);
910-
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "findMethodHandle", result.notEqual(nullHandle()), stackTrace, name, paramTypes);
874+
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "findMethodHandle", declaringClass.notEqual(nullHandle()) && name != null, stackTrace, name, paramTypes);
911875
return true;
912876
}
913877

914-
private static boolean findConstructorHandle(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
878+
private static boolean findConstructorHandle(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
915879
JNIObjectHandle callerClass = state.getDirectCallerClass();
916-
JNIObjectHandle lookup = getReceiver(thread);
917880
JNIObjectHandle declaringClass = getObjectArgument(thread, 1);
918881
JNIObjectHandle methodType = getObjectArgument(thread, 2);
919882

920-
JNIObjectHandle result = Support.callObjectMethodLL(jni, lookup, bp.method, declaringClass, methodType);
921-
result = shouldIncludeMethod(jni, result, agent.handles().javaLangIllegalAccessException);
922-
923883
Object paramTypes = getClassArrayNames(jni, getParamTypes(jni, methodType));
924-
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "findConstructorHandle", result.notEqual(nullHandle()), state.getFullStackTraceOrNull(), paramTypes);
884+
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "findConstructorHandle", declaringClass.notEqual(nullHandle()), state.getFullStackTraceOrNull(), paramTypes);
925885
return true;
926886
}
927887

@@ -933,42 +893,29 @@ private static JNIObjectHandle getParamTypes(JNIEnvironment jni, JNIObjectHandle
933893
return paramTypesHandle;
934894
}
935895

936-
private static boolean findFieldHandle(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
896+
private static boolean findFieldHandle(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
937897
JNIObjectHandle callerClass = state.getDirectCallerClass();
938-
JNIObjectHandle lookup = getReceiver(thread);
939898
JNIObjectHandle declaringClass = getObjectArgument(thread, 1);
940899
JNIObjectHandle fieldName = getObjectArgument(thread, 2);
941-
JNIObjectHandle fieldType = getObjectArgument(thread, 3);
942-
943-
JNIObjectHandle result = Support.callObjectMethodLLL(jni, lookup, bp.method, declaringClass, fieldName, fieldType);
944-
result = shouldIncludeMethod(jni, result, agent.handles().javaLangIllegalAccessException);
945900

946901
String name = fromJniString(jni, fieldName);
947-
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "findFieldHandle", result.notEqual(nullHandle()), state.getFullStackTraceOrNull(), name);
902+
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "findFieldHandle", declaringClass.notEqual(nullHandle()) && name != null, state.getFullStackTraceOrNull(), name);
948903
return true;
949904
}
950905

951906
private static boolean findClass(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
952907
JNIObjectHandle callerClass = state.getDirectCallerClass();
953-
JNIObjectHandle lookup = getReceiver(thread);
954908
JNIObjectHandle className = getObjectArgument(thread, 1);
955909

956-
JNIObjectHandle result = Support.callObjectMethodL(jni, lookup, bp.method, className);
957-
result = shouldIncludeMethod(jni, result, agent.handles().javaLangIllegalAccessException);
958-
959910
String name = fromJniString(jni, className);
960-
traceReflectBreakpoint(jni, bp.clazz, nullHandle(), callerClass, "findClass", result.notEqual(nullHandle()), state.getFullStackTraceOrNull(), name);
911+
traceReflectBreakpoint(jni, bp.clazz, nullHandle(), callerClass, "findClass", name != null, state.getFullStackTraceOrNull(), name);
961912
return true;
962913
}
963914

964-
private static boolean unreflectField(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
915+
private static boolean unreflectField(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
965916
JNIObjectHandle callerClass = state.getDirectCallerClass();
966-
JNIObjectHandle lookup = getReceiver(thread);
967917
JNIObjectHandle field = getObjectArgument(thread, 1);
968918

969-
JNIObjectHandle result = Support.callObjectMethodL(jni, lookup, bp.method, field);
970-
result = shouldIncludeMethod(jni, result, agent.handles().javaLangIllegalAccessException);
971-
972919
JNIObjectHandle declaringClass = Support.callObjectMethod(jni, field, agent.handles().javaLangReflectMemberGetDeclaringClass);
973920
if (clearException(jni)) {
974921
declaringClass = nullHandle();
@@ -980,46 +927,34 @@ private static boolean unreflectField(JNIEnvironment jni, JNIObjectHandle thread
980927
}
981928

982929
String fieldName = fromJniString(jni, fieldNameHandle);
983-
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "unreflectField", result.notEqual(nullHandle()), state.getFullStackTraceOrNull(), fieldName);
930+
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "unreflectField", declaringClass.notEqual(nullHandle()) && fieldName != null, state.getFullStackTraceOrNull(),
931+
fieldName);
984932
return true;
985933
}
986934

987-
private static boolean asInterfaceInstance(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
935+
private static boolean asInterfaceInstance(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
988936
JNIObjectHandle callerClass = state.getDirectCallerClass();
989937
JNIObjectHandle intfc = getObjectArgument(thread, 0);
990-
JNIObjectHandle methodHandle = getObjectArgument(thread, 1);
991-
992-
JNIObjectHandle result = Support.callStaticObjectMethodLL(jni, bp.clazz, bp.method, intfc, methodHandle);
993-
result = shouldIncludeMethod(jni, result, agent.handles().javaLangInvokeWrongMethodTypeException, agent.handles().javaLangIllegalArgumentException);
994938

995939
JNIObjectHandle intfcNameHandle = Support.callObjectMethod(jni, intfc, agent.handles().javaLangClassGetName);
996940
if (clearException(jni)) {
997941
intfcNameHandle = nullHandle();
998942
}
999943
String intfcName = fromJniString(jni, intfcNameHandle);
1000-
traceReflectBreakpoint(jni, intfc, nullHandle(), callerClass, "asInterfaceInstance", result.notEqual(nullHandle()), state.getFullStackTraceOrNull());
944+
traceReflectBreakpoint(jni, intfc, nullHandle(), callerClass, "asInterfaceInstance", intfcName != null, state.getFullStackTraceOrNull());
1001945
String[] intfcNames = new String[]{intfcName};
1002-
traceReflectBreakpoint(jni, nullHandle(), nullHandle(), callerClass, "newMethodHandleProxyInstance", result.notEqual(nullHandle()), state.getFullStackTraceOrNull(), (Object) intfcNames);
946+
traceReflectBreakpoint(jni, nullHandle(), nullHandle(), callerClass, "newMethodHandleProxyInstance", intfcName != null, state.getFullStackTraceOrNull(), (Object) intfcNames);
1003947
return true;
1004948
}
1005949

1006-
private static boolean constantBootstrapGetStaticFinal(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state, boolean hasDeclaringClass) {
950+
private static boolean constantBootstrapGetStaticFinal(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state, boolean hasDeclaringClass) {
1007951
JNIObjectHandle callerClass = state.getDirectCallerClass();
1008-
JNIObjectHandle lookup = getObjectArgument(thread, 0);
1009952
JNIObjectHandle fieldName = getObjectArgument(thread, 1);
1010953
JNIObjectHandle type = getObjectArgument(thread, 2);
1011954
JNIObjectHandle declaringClass = hasDeclaringClass ? getObjectArgument(thread, 3) : type;
1012955

1013-
JNIObjectHandle result;
1014-
if (hasDeclaringClass) {
1015-
result = Support.callStaticObjectMethodLLLL(jni, bp.clazz, bp.method, lookup, fieldName, type, declaringClass);
1016-
} else {
1017-
result = Support.callStaticObjectMethodLLL(jni, bp.clazz, bp.method, lookup, fieldName, type);
1018-
}
1019-
result = shouldIncludeMethod(jni, result, agent.handles().javaLangIllegalAccessError);
1020-
1021956
String name = fromJniString(jni, fieldName);
1022-
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "findFieldHandle", result.notEqual(nullHandle()), state.getFullStackTraceOrNull(), name);
957+
traceReflectBreakpoint(jni, declaringClass, nullHandle(), callerClass, "findFieldHandle", declaringClass.notEqual(nullHandle()) && name != null, state.getFullStackTraceOrNull(), name);
1023958
return true;
1024959
}
1025960

@@ -1058,24 +993,6 @@ private static boolean methodTypeFromDescriptor(JNIEnvironment jni, JNIObjectHan
1058993
return true;
1059994
}
1060995

1061-
private static JNIObjectHandle shouldIncludeMethod(JNIEnvironment jni, JNIObjectHandle result, JNIObjectHandle... acceptedExceptions) {
1062-
JNIObjectHandle exception = handleException(jni, true);
1063-
if (exception.notEqual(nullHandle())) {
1064-
for (JNIObjectHandle acceptedException : acceptedExceptions) {
1065-
if (jniFunctions().getIsInstanceOf().invoke(jni, exception, acceptedException)) {
1066-
/*
1067-
* We include methods if the lookup returned an IllegalAccessException or a
1068-
* WrongMethodTypeException to make sure the right exception is thrown at
1069-
* runtime, instead of a NoSuchMethodException.
1070-
*/
1071-
return JNIObjectHandles.createLocal(Boolean.TRUE);
1072-
}
1073-
}
1074-
return nullHandle();
1075-
}
1076-
return result;
1077-
}
1078-
1079996
/**
1080997
* We have to find a class that captures a lambda function so it can be registered by the agent.
1081998
* We have to get a SerializedLambda instance first. After that we get a lambda capturing class

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,13 @@ public static void registerClass(Class<?> clazz) {
5555
return; // must be defined at runtime before it can be looked up
5656
}
5757
String name = clazz.getName();
58-
if (!singleton().knownClasses.containsKey(name) || !(singleton().knownClasses.get(name) instanceof Throwable)) {
59-
/*
60-
* If the class has already been seen as throwing an error, we don't overwrite this
61-
* error
62-
*/
63-
VMError.guarantee(!singleton().knownClasses.containsKey(name) || singleton().knownClasses.get(name) == clazz);
64-
singleton().knownClasses.put(name, clazz);
65-
}
58+
Object currentValue = singleton().knownClasses.get(name);
59+
VMError.guarantee(currentValue == null || currentValue == clazz || currentValue instanceof Throwable,
60+
"Invalid Class.forName value for %s: %s", name, currentValue);
61+
/*
62+
* If the class has already been seen as throwing an error, we don't overwrite this error
63+
*/
64+
singleton().knownClasses.putIfAbsent(name, clazz);
6665
}
6766

6867
@Platforms(Platform.HOSTED_ONLY.class)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/MissingReflectionRegistrationUtils.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ public static void forField(Class<?> declaringClass, String fieldName) {
5656

5757
public static void forMethod(Class<?> declaringClass, String methodName, Class<?>[] paramTypes) {
5858
StringJoiner paramTypeNames = new StringJoiner(", ", "(", ")");
59-
for (Class<?> paramType : paramTypes) {
60-
paramTypeNames.add(paramType.getTypeName());
59+
if (paramTypes != null) {
60+
for (Class<?> paramType : paramTypes) {
61+
paramTypeNames.add(paramType.getTypeName());
62+
}
6163
}
6264
MissingReflectionRegistrationError exception = new MissingReflectionRegistrationError(errorMessage("access method",
6365
declaringClass.getTypeName() + "#" + methodName + paramTypeNames),

0 commit comments

Comments
 (0)