Skip to content

Commit

Permalink
[GR-54742] Support class file format errors in method parameter encod…
Browse files Browse the repository at this point in the history
…ings.

PullRequest: graal/18040
  • Loading branch information
christianwimmer committed Jun 17, 2024
2 parents 860a1a8 + 8a76040 commit f300d95
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ public Object[] parseObjects(int index) {
}

/**
* Parameters encoding for executables.
* Parameters encoding for executables. Note that this method can re-throw an exception that was
* caught and encoded at image build time.
*
* <pre>
* ParameterMetadata[] parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ private Parameter[] getParameters0() {
if (rawParameters == null) {
return null;
}
/*
* Note that the rawParameters encoding can also encode a possible IllegalArgumentException.
* We want the decoder to throw this exception. Our caller Executable.parameterData catches
* it and converts it to a class format error.
*/
return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseReflectParameters(SubstrateUtil.cast(this, Executable.class), rawParameters);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,12 @@ static class ExecutableMetadata extends AccessibleObjectMetadata {
final Object[] parameterTypes;
final HostedType[] exceptionTypes;
final AnnotationValue[][] parameterAnnotations;
final ReflectParameterMetadata[] reflectParameters;
final Object reflectParameters;
final JavaConstant accessor;

ExecutableMetadata(RuntimeConditionSet conditions, boolean complete, boolean negative, JavaConstant heapObject, HostedType declaringType, Object[] parameterTypes, int modifiers,
HostedType[] exceptionTypes, String signature,
AnnotationValue[] annotations, AnnotationValue[][] parameterAnnotations, TypeAnnotationValue[] typeAnnotations, ReflectParameterMetadata[] reflectParameters,
AnnotationValue[] annotations, AnnotationValue[][] parameterAnnotations, TypeAnnotationValue[] typeAnnotations, Object reflectParameters,
JavaConstant accessor) {
super(conditions, complete, negative, heapObject, declaringType, modifiers, signature, annotations, typeAnnotations);

Expand All @@ -163,7 +163,7 @@ static class MethodMetadata extends ExecutableMetadata {
private MethodMetadata(RuntimeConditionSet conditions, boolean complete, boolean negative, boolean hiding, JavaConstant heapObject, HostedType declaringClass, String name,
Object[] parameterTypes, int modifiers,
HostedType returnType, HostedType[] exceptionTypes, String signature, AnnotationValue[] annotations, AnnotationValue[][] parameterAnnotations,
AnnotationMemberValue annotationDefault, TypeAnnotationValue[] typeAnnotations, ReflectParameterMetadata[] reflectParameters, JavaConstant accessor) {
AnnotationMemberValue annotationDefault, TypeAnnotationValue[] typeAnnotations, Object reflectParameters, JavaConstant accessor) {
super(conditions, complete, negative, heapObject, declaringClass, parameterTypes, modifiers, exceptionTypes, signature, annotations, parameterAnnotations, typeAnnotations,
reflectParameters,
accessor);
Expand All @@ -177,15 +177,15 @@ private MethodMetadata(RuntimeConditionSet conditions, boolean complete, boolean
MethodMetadata(RuntimeConditionSet conditions, HostedType declaringClass, String name, HostedType[] parameterTypes, int modifiers, HostedType returnType, HostedType[] exceptionTypes,
String signature,
AnnotationValue[] annotations, AnnotationValue[][] parameterAnnotations, AnnotationMemberValue annotationDefault, TypeAnnotationValue[] typeAnnotations,
ReflectParameterMetadata[] reflectParameters, JavaConstant accessor) {
Object reflectParameters, JavaConstant accessor) {
this(conditions, true, false, false, null, declaringClass, name, parameterTypes, modifiers, returnType, exceptionTypes, signature, annotations, parameterAnnotations, annotationDefault,
typeAnnotations, reflectParameters, accessor);
}

/* Method in heap */
MethodMetadata(RuntimeConditionSet conditions, boolean registered, JavaConstant heapObject, AnnotationValue[] annotations, AnnotationValue[][] parameterAnnotations,
AnnotationMemberValue annotationDefault,
TypeAnnotationValue[] typeAnnotations, ReflectParameterMetadata[] reflectParameters) {
TypeAnnotationValue[] typeAnnotations, Object reflectParameters) {
this(conditions, registered, false, false, heapObject, null, null, null, 0, null, null, null, annotations, parameterAnnotations, annotationDefault,
typeAnnotations,
reflectParameters, null);
Expand All @@ -211,7 +211,7 @@ static class ConstructorMetadata extends ExecutableMetadata {

private ConstructorMetadata(RuntimeConditionSet conditions, boolean complete, boolean negative, JavaConstant heapObject, HostedType declaringClass, Object[] parameterTypes, int modifiers,
HostedType[] exceptionTypes,
String signature, AnnotationValue[] annotations, AnnotationValue[][] parameterAnnotations, TypeAnnotationValue[] typeAnnotations, ReflectParameterMetadata[] reflectParameters,
String signature, AnnotationValue[] annotations, AnnotationValue[][] parameterAnnotations, TypeAnnotationValue[] typeAnnotations, Object reflectParameters,
JavaConstant accessor) {
super(conditions, complete, negative, heapObject, declaringClass, parameterTypes, modifiers, exceptionTypes, signature, annotations, parameterAnnotations, typeAnnotations,
reflectParameters,
Expand All @@ -221,14 +221,14 @@ private ConstructorMetadata(RuntimeConditionSet conditions, boolean complete, bo
/* Constructor registered for reflection */
ConstructorMetadata(RuntimeConditionSet conditions, HostedType declaringClass, HostedType[] parameterTypes, int modifiers, HostedType[] exceptionTypes, String signature,
AnnotationValue[] annotations,
AnnotationValue[][] parameterAnnotations, TypeAnnotationValue[] typeAnnotations, ReflectParameterMetadata[] reflectParameters, JavaConstant accessor) {
AnnotationValue[][] parameterAnnotations, TypeAnnotationValue[] typeAnnotations, Object reflectParameters, JavaConstant accessor) {
this(conditions, true, false, null, declaringClass, parameterTypes, modifiers, exceptionTypes, signature, annotations, parameterAnnotations, typeAnnotations, reflectParameters, accessor);
}

/* Constructor in heap */
ConstructorMetadata(RuntimeConditionSet conditions, boolean registered, JavaConstant heapObject, AnnotationValue[] annotations, AnnotationValue[][] parameterAnnotations,
TypeAnnotationValue[] typeAnnotations,
ReflectParameterMetadata[] reflectParameters) {
Object reflectParameters) {
this(conditions, registered, false, heapObject, null, null, 0, null, null, annotations, parameterAnnotations, typeAnnotations, reflectParameters, null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ public void addReflectionExecutableMetadata(MetaAccessProvider metaAccess, Hoste
AnnotationValue[][] parameterAnnotations = registerParameterAnnotationValues(analysisMethod);
AnnotationMemberValue annotationDefault = isMethod ? registerAnnotationDefaultValues(analysisMethod) : null;
TypeAnnotationValue[] typeAnnotations = registerTypeAnnotationValues(analysisMethod);
ReflectParameterMetadata[] reflectParameters = registerReflectParameters(reflectMethod);
Object reflectParameters = registerReflectParameters(reflectMethod);
JavaConstant accessorConstant = null;
if (accessor != null) {
accessorConstant = snippetReflection.forObject(accessor);
Expand Down Expand Up @@ -487,7 +487,7 @@ public void addHeapAccessibleObjectMetadata(MetaAccessProvider metaAccess, Wrapp
AnnotationValue[][] parameterAnnotations = isExecutable ? registerParameterAnnotationValues((AnalysisMethod) analysisObject) : null;
TypeAnnotationValue[] typeAnnotations = registerTypeAnnotationValues(analysisObject);
AnnotationMemberValue annotationDefault = isMethod ? registerAnnotationDefaultValues((AnalysisMethod) analysisObject) : null;
ReflectParameterMetadata[] reflectParameters = isExecutable ? registerReflectParameters((Executable) object) : null;
Object reflectParameters = isExecutable ? registerReflectParameters((Executable) object) : null;
AccessibleObject holder = RuntimeMetadataEncoder.getHolder(object);
JavaConstant heapObjectConstant = snippetReflection.forObject(holder);
addConstantObject(heapObjectConstant);
Expand Down Expand Up @@ -563,11 +563,15 @@ private void registerValues(AnnotationMemberValue annotationValue) {
AnnotationMetadataEncoder.registerAnnotationMember(annotationValue, encoders, snippetReflection);
}

private ReflectParameterMetadata[] registerReflectParameters(Executable executable) {
ReflectParameterMetadata[] reflectParameters = getReflectParameters(executable);
private Object registerReflectParameters(Executable executable) {
Object reflectParameters = getReflectParameters(executable);
if (reflectParameters != null) {
for (ReflectParameterMetadata parameter : reflectParameters) {
encoders.otherStrings.addObject(parameter.name);
if (reflectParameters instanceof Throwable paramError) {
registerError(paramError);
} else {
for (ReflectParameterMetadata parameter : (ReflectParameterMetadata[]) reflectParameters) {
encoders.otherStrings.addObject(parameter.name);
}
}
}
return reflectParameters;
Expand Down Expand Up @@ -705,8 +709,18 @@ private static HostedType[] getExceptionTypes(MetaAccessProvider metaAccess, Exe
return exceptionTypes;
}

private static ReflectParameterMetadata[] getReflectParameters(Executable reflectMethod) {
Parameter[] rawParameters = getRawParameters(reflectMethod);
private static Object getReflectParameters(Executable reflectMethod) {
Parameter[] rawParameters;
try {
rawParameters = ReflectionUtil.invokeMethod(getExecutableParameters, reflectMethod);
} catch (IllegalArgumentException ex) {
/*
* Executable.parameterData catches this exception and then reports it as a class format
* error. We need to do preserve the exception and re-throw it at image run time.
*/
return ex;
}

if (rawParameters == null) {
return null;
}
Expand Down Expand Up @@ -955,6 +969,16 @@ private void encodeObject(UnsafeArrayTypeWriter buf, JavaConstant object) {
}
}

private <T> void encodeArrayOrError(UnsafeArrayTypeWriter buf, Object arrayOrError, Consumer<T> elementEncoder) {
if (arrayOrError instanceof Throwable error) {
buf.putSV(encodeErrorIndex(error));
} else {
@SuppressWarnings("unchecked")
T[] array = (T[]) arrayOrError;
encodeArray(buf, array, elementEncoder);
}
}

private static <T> void encodeArray(UnsafeArrayTypeWriter buf, T[] array, Consumer<T> elementEncoder) {
buf.putSV(array.length);
for (T elem : array) {
Expand Down Expand Up @@ -998,14 +1022,6 @@ private static String getSignature(Executable executable) {
}
}

private static Parameter[] getRawParameters(Executable executable) {
try {
return (Parameter[]) getExecutableParameters.invoke(executable);
} catch (IllegalAccessException | InvocationTargetException e) {
throw VMError.shouldNotReachHere(e);
}
}

/**
* The following methods encode annotations attached to a method or parameter in a format based
* on the one used internally by the JDK ({@link sun.reflect.annotation.AnnotationParser}). The
Expand Down Expand Up @@ -1062,12 +1078,12 @@ private byte[] encodeTypeAnnotations(TypeAnnotationValue[] typeAnnotations) {
return buf.toArray();
}

private byte[] encodeReflectParameters(ReflectParameterMetadata[] reflectParameters) {
private byte[] encodeReflectParameters(Object reflectParameters) {
if (reflectParameters == null) {
return null;
}
UnsafeArrayTypeWriter buf = UnsafeArrayTypeWriter.create(ByteArrayReader.supportsUnalignedMemoryAccess());
encodeArray(buf, reflectParameters, reflectParameter -> encodeReflectParameter(buf, reflectParameter));
encodeArrayOrError(buf, reflectParameters, (ReflectParameterMetadata reflectParameter) -> encodeReflectParameter(buf, reflectParameter));
return buf.toArray();
}

Expand Down

0 comments on commit f300d95

Please sign in to comment.