Skip to content

Commit 5017f9b

Browse files
author
Christian Wimmer
committed
[GR-36044] Catch exceptions thrown during annotation parsing.
PullRequest: graal/13371
2 parents 9fe98a9 + 10d9200 commit 5017f9b

File tree

5 files changed

+86
-30
lines changed

5 files changed

+86
-30
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_sun_reflect_annotation_AnnotationParser.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ private static Annotation parseAnnotation2(ByteBuffer buf,
6262
boolean exceptionOnMissingAnnotationClass,
6363
Class<? extends Annotation>[] selectAnnotationClasses) {
6464
int typeIndex = buf.getInt();
65+
if (typeIndex < 0) {
66+
throw new AnnotationFormatError("Annotations could not be parsed at image build time");
67+
}
6568
Class<? extends Annotation> annotationClass;
6669
try {
6770
annotationClass = (Class<? extends Annotation>) constPool.getClassAt(typeIndex);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationValue.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
package com.oracle.svm.hosted.annotation;
2626

2727
import java.lang.annotation.Annotation;
28+
import java.lang.annotation.AnnotationFormatError;
2829
import java.lang.reflect.InvocationTargetException;
2930
import java.nio.ByteBuffer;
3031
import java.util.ArrayList;
@@ -73,6 +74,16 @@ static AnnotationValue extract(ByteBuffer buf, ConstantPool cp, Class<?> contain
7374
return new AnnotationValue(type, memberValues);
7475
}
7576

77+
/**
78+
* When the byte[] array for the annotation cannot be parsed at build time, anything can be
79+
* wrong - it could be just random garbage of bytes. We do not need to register exactly what
80+
* went wrong during parsing, we just register a marker to throw an AnnotationFormatException
81+
* when parsing the data at run time again.
82+
*/
83+
static AnnotationValue forAnnotationFormatException() {
84+
return new AnnotationValue(null, null);
85+
}
86+
7687
AnnotationValue(Annotation annotation) {
7788
this.type = annotation.annotationType();
7889
this.members = new LinkedHashMap<>();
@@ -96,6 +107,10 @@ private AnnotationValue(Class<? extends Annotation> type, Map<String, Annotation
96107
this.members = members;
97108
}
98109

110+
public boolean isAnnotationFormatException() {
111+
return type == null && members == null;
112+
}
113+
99114
public Class<? extends Annotation> getType() {
100115
return type;
101116
}
@@ -110,6 +125,9 @@ public void forEachMember(BiConsumer<String, AnnotationMemberValue> callback) {
110125

111126
@Override
112127
public List<Class<?>> getTypes() {
128+
if (isAnnotationFormatException()) {
129+
return List.of();
130+
}
113131
List<Class<?>> types = new ArrayList<>();
114132
types.add(type);
115133
for (AnnotationMemberValue memberValue : members.values()) {
@@ -120,6 +138,9 @@ public List<Class<?>> getTypes() {
120138

121139
@Override
122140
public List<String> getStrings() {
141+
if (isAnnotationFormatException()) {
142+
return List.of();
143+
}
123144
List<String> strings = new ArrayList<>();
124145
members.forEach((memberName, memberValue) -> {
125146
strings.add(memberName);
@@ -130,6 +151,9 @@ public List<String> getStrings() {
130151

131152
@Override
132153
public List<JavaConstant> getExceptionProxies() {
154+
if (isAnnotationFormatException()) {
155+
return List.of();
156+
}
133157
List<JavaConstant> exceptionProxies = new ArrayList<>();
134158
for (AnnotationMemberValue memberValue : members.values()) {
135159
exceptionProxies.addAll(memberValue.getExceptionProxies());
@@ -144,6 +168,9 @@ public char getTag() {
144168

145169
@Override
146170
public Object get(Class<?> memberType) {
171+
if (isAnnotationFormatException()) {
172+
throw new AnnotationFormatError("Annotations could not be parsed at image build time");
173+
}
147174
AnnotationType annotationType = AnnotationType.getInstance(type);
148175
Map<String, Object> memberValues = new LinkedHashMap<>(annotationType.memberDefaults());
149176
members.forEach((memberName, memberValue) -> memberValues.put(memberName, memberValue.get(annotationType.memberTypes().get(memberName))));
@@ -159,11 +186,11 @@ public boolean equals(Object o) {
159186
return false;
160187
}
161188
AnnotationValue that = (AnnotationValue) o;
162-
return Objects.equals(type, that.type) && members.equals(that.members);
189+
return isAnnotationFormatException() == that.isAnnotationFormatException() && Objects.equals(type, that.type) && members.equals(that.members);
163190
}
164191

165192
@Override
166193
public int hashCode() {
167-
return Objects.hash(type, members);
194+
return Objects.hash(isAnnotationFormatException(), type, members);
168195
}
169196
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.lang.reflect.Field;
3333
import java.lang.reflect.InvocationTargetException;
3434
import java.lang.reflect.Method;
35+
import java.nio.BufferUnderflowException;
3536
import java.nio.ByteBuffer;
3637
import java.util.ArrayList;
3738
import java.util.Arrays;
@@ -149,7 +150,7 @@ public boolean hasAnnotation(AnnotatedElement element, Class<? extends Annotatio
149150
@SuppressWarnings("unchecked")
150151
@Override
151152
public Class<? extends Annotation>[] getAnnotationTypes(AnnotatedElement element) {
152-
return Arrays.stream(getAnnotationData(element, false)).map(AnnotationValue::getType).toArray(Class[]::new);
153+
return Arrays.stream(getAnnotationData(element, false)).map(AnnotationValue::getType).filter(t -> t != null).toArray(Class[]::new);
153154
}
154155

155156
public AnnotationValue[] getDeclaredAnnotationData(AnnotatedElement element) {
@@ -220,15 +221,19 @@ private AnnotationValue[] getDeclaredAnnotationDataFromRoot(AnnotatedElement roo
220221
return NO_ANNOTATIONS;
221222
}
222223
ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
223-
List<AnnotationValue> annotations = new ArrayList<>();
224-
int numAnnotations = buf.getShort() & 0xFFFF;
225-
for (int i = 0; i < numAnnotations; i++) {
226-
AnnotationValue annotation = AnnotationValue.extract(buf, getConstantPool(element), getContainer(element), false, false);
227-
if (annotation != null) {
228-
annotations.add(annotation);
224+
try {
225+
List<AnnotationValue> annotations = new ArrayList<>();
226+
int numAnnotations = buf.getShort() & 0xFFFF;
227+
for (int i = 0; i < numAnnotations; i++) {
228+
AnnotationValue annotation = AnnotationValue.extract(buf, getConstantPool(element), getContainer(element), false, false);
229+
if (annotation != null) {
230+
annotations.add(annotation);
231+
}
229232
}
233+
return annotations.toArray(NO_ANNOTATIONS);
234+
} catch (IllegalArgumentException | BufferUnderflowException ex) {
235+
return new AnnotationValue[]{AnnotationValue.forAnnotationFormatException()};
230236
}
231-
return annotations.toArray(NO_ANNOTATIONS);
232237
});
233238
}
234239

@@ -244,20 +249,24 @@ private AnnotationValue[][] getParameterAnnotationDataFromRoot(Executable rootEl
244249
return NO_PARAMETER_ANNOTATIONS;
245250
}
246251
ByteBuffer buf = ByteBuffer.wrap(rawParameterAnnotations);
247-
int numParameters = buf.get() & 0xFF;
248-
AnnotationValue[][] parameterAnnotations = new AnnotationValue[numParameters][];
249-
for (int i = 0; i < numParameters; i++) {
250-
List<AnnotationValue> parameterAnnotationList = new ArrayList<>();
251-
int numAnnotations = buf.getShort() & 0xFFFF;
252-
for (int j = 0; j < numAnnotations; j++) {
253-
AnnotationValue parameterAnnotation = AnnotationValue.extract(buf, getConstantPool(element), getContainer(element), false, false);
254-
if (parameterAnnotation != null) {
255-
parameterAnnotationList.add(parameterAnnotation);
252+
try {
253+
int numParameters = buf.get() & 0xFF;
254+
AnnotationValue[][] parameterAnnotations = new AnnotationValue[numParameters][];
255+
for (int i = 0; i < numParameters; i++) {
256+
List<AnnotationValue> parameterAnnotationList = new ArrayList<>();
257+
int numAnnotations = buf.getShort() & 0xFFFF;
258+
for (int j = 0; j < numAnnotations; j++) {
259+
AnnotationValue parameterAnnotation = AnnotationValue.extract(buf, getConstantPool(element), getContainer(element), false, false);
260+
if (parameterAnnotation != null) {
261+
parameterAnnotationList.add(parameterAnnotation);
262+
}
256263
}
264+
parameterAnnotations[i] = parameterAnnotationList.toArray(NO_ANNOTATIONS);
257265
}
258-
parameterAnnotations[i] = parameterAnnotationList.toArray(NO_ANNOTATIONS);
266+
return parameterAnnotations;
267+
} catch (IllegalArgumentException | BufferUnderflowException ex) {
268+
return new AnnotationValue[][]{new AnnotationValue[]{AnnotationValue.forAnnotationFormatException()}};
259269
}
260-
return parameterAnnotations;
261270
});
262271
}
263272

@@ -273,12 +282,21 @@ private TypeAnnotationValue[] getTypeAnnotationDataFromRoot(AnnotatedElement roo
273282
return NO_TYPE_ANNOTATIONS;
274283
}
275284
ByteBuffer buf = ByteBuffer.wrap(rawTypeAnnotations);
276-
int annotationCount = buf.getShort() & 0xFFFF;
277-
TypeAnnotationValue[] typeAnnotationValues = new TypeAnnotationValue[annotationCount];
278-
for (int i = 0; i < annotationCount; i++) {
279-
typeAnnotationValues[i] = TypeAnnotationValue.extract(buf, getConstantPool(element), getContainer(element));
285+
try {
286+
int annotationCount = buf.getShort() & 0xFFFF;
287+
TypeAnnotationValue[] typeAnnotationValues = new TypeAnnotationValue[annotationCount];
288+
for (int i = 0; i < annotationCount; i++) {
289+
typeAnnotationValues[i] = TypeAnnotationValue.extract(buf, getConstantPool(element), getContainer(element));
290+
}
291+
return typeAnnotationValues;
292+
} catch (IllegalArgumentException | BufferUnderflowException ex) {
293+
/*
294+
* The byte[] arrrays in the TypeAnnotationValue are structurally correct, but have
295+
* an illegal first targetInfo byte that will throw an AnnotationFormatException
296+
* during parsing.
297+
*/
298+
return new TypeAnnotationValue[]{new TypeAnnotationValue(new byte[]{0x77}, new byte[]{0}, AnnotationValue.forAnnotationFormatException())};
280299
}
281-
return typeAnnotationValues;
282300
});
283301
}
284302

@@ -294,7 +312,11 @@ private AnnotationMemberValue getAnnotationDefaultDataFromRoot(Method accessorMe
294312
return null;
295313
}
296314
ByteBuffer buf = ByteBuffer.wrap(rawAnnotationDefault);
297-
return AnnotationMemberValue.extract(buf, getConstantPool(method), getContainer(method), false);
315+
try {
316+
return AnnotationMemberValue.extract(buf, getConstantPool(method), getContainer(method), false);
317+
} catch (IllegalArgumentException | BufferUnderflowException ex) {
318+
return AnnotationValue.forAnnotationFormatException();
319+
}
298320
});
299321
}
300322

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/TypeAnnotationValue.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ static TypeAnnotationValue extract(ByteBuffer buf, ConstantPool cp, Class<?> con
137137
return new TypeAnnotationValue(targetInfo, locationInfo, annotation);
138138
}
139139

140-
private TypeAnnotationValue(byte[] targetInfo, byte[] locationInfo, AnnotationValue annotation) {
140+
TypeAnnotationValue(byte[] targetInfo, byte[] locationInfo, AnnotationValue annotation) {
141141
this.targetInfo = targetInfo;
142142
this.locationInfo = locationInfo;
143143
this.annotation = annotation;

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/AnnotationEncoder.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242

4343
public class AnnotationEncoder {
4444
static void encodeAnnotation(UnsafeArrayTypeWriter buf, AnnotationValue value, Encoders encoders) {
45+
if (value.isAnnotationFormatException()) {
46+
buf.putS4(-1);
47+
return;
48+
}
4549
buf.putS4(encoders.sourceClasses.getIndex(value.getType()));
4650
buf.putU2(value.getMemberCount());
4751
value.forEachMember((memberName, memberValue) -> {
@@ -103,10 +107,10 @@ static void encodeAnnotationMember(UnsafeArrayTypeWriter buf, AnnotationMemberVa
103107

104108
static void encodeTypeAnnotation(UnsafeArrayTypeWriter buf, TypeAnnotationValue value, Encoders encoders) {
105109
for (byte b : value.getTargetInfo()) {
106-
buf.putU1(b);
110+
buf.putS1(b);
107111
}
108112
for (byte b : value.getLocationInfo()) {
109-
buf.putU1(b);
113+
buf.putS1(b);
110114
}
111115
encodeAnnotation(buf, value.getAnnotationData(), encoders);
112116
}

0 commit comments

Comments
 (0)