8313452: Improve Classfile API attributes handling safety

Reviewed-by: briangoetz
This commit is contained in:
Adam Sotona 2023-09-14 18:52:51 +00:00
parent 2a6fb9ce59
commit b2e91060db
10 changed files with 457 additions and 107 deletions

View File

@ -37,6 +37,41 @@ package jdk.internal.classfile;
*/
public interface AttributeMapper<A> {
/**
* Attribute stability indicator
*/
enum AttributeStability {
/**
* The attribute contains only pure data, such as timestamps, and can always be bulk-copied.
*/
STATELESS,
/**
* The attribute contains only pure data and CP refs, so can be bulk-copied when CP sharing is in effect,
* and need to be exploded and rewritten when CP sharing is not in effect.
*/
CP_REFS,
/**
* The attribute may contain labels, so need to be exploded and rewritten when the Code array is perturbed.
*/
LABELS,
/**
* The attribute may contain indexes into structured not managed by the library (type variable lists, etc)
* and so we consult the {@link Classfile.AttributesProcessingOption} option to determine whether to preserve
* or drop it during transformation.
*/
UNSTABLE,
/**
* The attribute is completely unknown and so we consult the {@link Classfile.AttributesProcessingOption} option
* to determine whether to preserve or drop it during transformation.
*/
UNKNOWN
}
/**
* {@return the name of the attribute}
*/
@ -75,4 +110,9 @@ public interface AttributeMapper<A> {
default boolean allowMultiple() {
return false;
}
/**
* {@return attribute stability indicator}
*/
AttributeStability stability();
}

View File

@ -215,6 +215,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, AnnotationDefaultAttribute attr) {
attr.defaultValue().writeTo(buf);
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code BootstrapMethods} attribute */
@ -229,6 +234,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, BootstrapMethodsAttribute attr) {
buf.writeList(attr.bootstrapMethods());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code CharacterRangeTable} attribute */
@ -251,6 +261,11 @@ public class Attributes {
buf.writeU2(info.flags());
}
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.LABELS;
}
};
/** Attribute mapper for the {@code Code} attribute */
@ -265,6 +280,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, CodeAttribute attr) {
throw new UnsupportedOperationException("Code attribute does not support direct write");
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
@ -280,6 +300,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, CompilationIDAttribute attr) {
buf.writeIndex(attr.compilationId());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code ConstantValue} attribute */
@ -294,6 +319,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, ConstantValueAttribute attr) {
buf.writeIndex(attr.constant());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code Deprecated} attribute */
@ -308,6 +338,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, DeprecatedAttribute attr) {
// empty
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.STATELESS;
}
};
/** Attribute mapper for the {@code EnclosingMethod} attribute */
@ -323,6 +358,11 @@ public class Attributes {
buf.writeIndex(attr.enclosingClass());
buf.writeIndexOrZero(attr.enclosingMethod().orElse(null));
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code Exceptions} attribute */
@ -337,6 +377,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, ExceptionsAttribute attr) {
buf.writeListIndices(attr.exceptions());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code InnerClasses} attribute */
@ -358,6 +403,11 @@ public class Attributes {
buf.writeU2(ic.flagsMask());
}
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code LineNumberTable} attribute */
@ -377,6 +427,11 @@ public class Attributes {
buf.writeU2(line.lineNumber());
}
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.LABELS;
}
};
/** Attribute mapper for the {@code LocalVariableTable} attribute */
@ -399,6 +454,11 @@ public class Attributes {
buf.writeU2(info.slot());
}
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.LABELS;
}
};
/** Attribute mapper for the {@code LocalVariableTypeTable} attribute */
@ -421,6 +481,11 @@ public class Attributes {
buf.writeU2(info.slot());
}
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.LABELS;
}
};
/** Attribute mapper for the {@code MethodParameters} attribute */
@ -440,47 +505,57 @@ public class Attributes {
buf.writeU2(info.flagsMask());
}
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code Module} attribute */
public static final AttributeMapper<ModuleAttribute>
MODULE = new AbstractAttributeMapper<>(NAME_MODULE, Classfile.JAVA_9_VERSION) {
@Override
public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
return new BoundAttribute.BoundModuleAttribute(cf, this, p);
}
@Override
public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) {
return new BoundAttribute.BoundModuleAttribute(cf, this, p);
}
@Override
protected void writeBody(BufWriter buf, ModuleAttribute attr) {
buf.writeIndex(attr.moduleName());
buf.writeU2(attr.moduleFlagsMask());
buf.writeIndexOrZero(attr.moduleVersion().orElse(null));
buf.writeU2(attr.requires().size());
for (ModuleRequireInfo require : attr.requires()) {
buf.writeIndex(require.requires());
buf.writeU2(require.requiresFlagsMask());
buf.writeIndexOrZero(require.requiresVersion().orElse(null));
}
buf.writeU2(attr.exports().size());
for (ModuleExportInfo export : attr.exports()) {
buf.writeIndex(export.exportedPackage());
buf.writeU2(export.exportsFlagsMask());
buf.writeListIndices(export.exportsTo());
}
buf.writeU2(attr.opens().size());
for (ModuleOpenInfo open : attr.opens()) {
buf.writeIndex(open.openedPackage());
buf.writeU2(open.opensFlagsMask());
buf.writeListIndices(open.opensTo());
}
buf.writeListIndices(attr.uses());
buf.writeU2(attr.provides().size());
for (ModuleProvideInfo provide : attr.provides()) {
buf.writeIndex(provide.provides());
buf.writeListIndices(provide.providesWith());
}
}
};
@Override
protected void writeBody(BufWriter buf, ModuleAttribute attr) {
buf.writeIndex(attr.moduleName());
buf.writeU2(attr.moduleFlagsMask());
buf.writeIndexOrZero(attr.moduleVersion().orElse(null));
buf.writeU2(attr.requires().size());
for (ModuleRequireInfo require : attr.requires()) {
buf.writeIndex(require.requires());
buf.writeU2(require.requiresFlagsMask());
buf.writeIndexOrZero(require.requiresVersion().orElse(null));
}
buf.writeU2(attr.exports().size());
for (ModuleExportInfo export : attr.exports()) {
buf.writeIndex(export.exportedPackage());
buf.writeU2(export.exportsFlagsMask());
buf.writeListIndices(export.exportsTo());
}
buf.writeU2(attr.opens().size());
for (ModuleOpenInfo open : attr.opens()) {
buf.writeIndex(open.openedPackage());
buf.writeU2(open.opensFlagsMask());
buf.writeListIndices(open.opensTo());
}
buf.writeListIndices(attr.uses());
buf.writeU2(attr.provides().size());
for (ModuleProvideInfo provide : attr.provides()) {
buf.writeIndex(provide.provides());
buf.writeListIndices(provide.providesWith());
}
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code ModuleHashes} attribute */
public static final AttributeMapper<ModuleHashesAttribute>
@ -501,6 +576,11 @@ public class Attributes {
buf.writeBytes(hash.hash());
}
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code ModuleMainClass} attribute */
@ -515,6 +595,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, ModuleMainClassAttribute attr) {
buf.writeIndex(attr.mainClass());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code ModulePackages} attribute */
@ -529,6 +614,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) {
buf.writeListIndices(attr.packages());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code ModuleResolution} attribute */
@ -543,6 +633,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, ModuleResolutionAttribute attr) {
buf.writeU2(attr.resolutionFlags());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.STATELESS;
}
};
/** Attribute mapper for the {@code ModuleTarget} attribute */
@ -557,6 +652,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, ModuleTargetAttribute attr) {
buf.writeIndex(attr.targetPlatform());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code NestHost} attribute */
@ -571,6 +671,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, NestHostAttribute attr) {
buf.writeIndex(attr.nestHost());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code NestMembers} attribute */
@ -585,6 +690,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, NestMembersAttribute attr) {
buf.writeListIndices(attr.nestMembers());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code PermittedSubclasses} attribute */
@ -599,6 +709,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, PermittedSubclassesAttribute attr) {
buf.writeListIndices(attr.permittedSubclasses());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code Record} attribute */
@ -619,6 +734,11 @@ public class Attributes {
buf.writeList(info.attributes());
}
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code RuntimeInvisibleAnnotations} attribute */
@ -633,7 +753,12 @@ public class Attributes {
protected void writeBody(BufWriter buf, RuntimeInvisibleAnnotationsAttribute attr) {
buf.writeList(attr.annotations());
}
};
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code RuntimeInvisibleParameterAnnotations} attribute */
public static final AttributeMapper<RuntimeInvisibleParameterAnnotationsAttribute>
@ -650,6 +775,11 @@ public class Attributes {
for (List<Annotation> list : lists)
buf.writeList(list);
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code RuntimeInvisibleTypeAnnotations} attribute */
@ -664,21 +794,31 @@ public class Attributes {
protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) {
buf.writeList(attr.annotations());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.UNSTABLE;
}
};
/** Attribute mapper for the {@code RuntimeVisibleAnnotations} attribute */
public static final AttributeMapper<RuntimeVisibleAnnotationsAttribute>
RUNTIME_VISIBLE_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_VISIBLE_ANNOTATIONS, Classfile.JAVA_5_VERSION) {
@Override
public RuntimeVisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) {
return new BoundAttribute.BoundRuntimeVisibleAnnotationsAttribute(cf, pos);
}
@Override
public RuntimeVisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) {
return new BoundAttribute.BoundRuntimeVisibleAnnotationsAttribute(cf, pos);
}
@Override
protected void writeBody(BufWriter buf, RuntimeVisibleAnnotationsAttribute attr) {
buf.writeList(attr.annotations());
}
};
@Override
protected void writeBody(BufWriter buf, RuntimeVisibleAnnotationsAttribute attr) {
buf.writeList(attr.annotations());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code RuntimeVisibleParameterAnnotations} attribute */
public static final AttributeMapper<RuntimeVisibleParameterAnnotationsAttribute>
@ -695,6 +835,11 @@ public class Attributes {
for (List<Annotation> list : lists)
buf.writeList(list);
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code RuntimeVisibleTypeAnnotations} attribute */
@ -709,6 +854,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) {
buf.writeList(attr.annotations());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.UNSTABLE;
}
};
/** Attribute mapper for the {@code Signature} attribute */
@ -723,6 +873,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, SignatureAttribute attr) {
buf.writeIndex(attr.signature());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code SourceDebugExtension} attribute */
@ -737,6 +892,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, SourceDebugExtensionAttribute attr) {
buf.writeBytes(attr.contents());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.STATELESS;
}
};
/** Attribute mapper for the {@code SourceFile} attribute */
@ -751,6 +911,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, SourceFileAttribute attr) {
buf.writeIndex(attr.sourceFile());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code SourceID} attribute */
@ -765,6 +930,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, SourceIDAttribute attr) {
buf.writeIndex(attr.sourceId());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.CP_REFS;
}
};
/** Attribute mapper for the {@code StackMapTable} attribute */
@ -779,6 +949,11 @@ public class Attributes {
protected void writeBody(BufWriter b, StackMapTableAttribute attr) {
StackMapDecoder.writeFrames(b, attr.entries());
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.LABELS;
}
};
@ -794,6 +969,11 @@ public class Attributes {
protected void writeBody(BufWriter buf, SyntheticAttribute attr) {
// empty
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.STATELESS;
}
};
/**

View File

@ -241,17 +241,22 @@ public sealed interface Classfile
}
/**
* Option describing whether to process or discard unrecognized attributes.
* Default is {@code PASS_UNKNOWN_ATTRIBUTES} to process unrecognized
* attributes, and deliver as instances of {@link UnknownAttribute}.
* Option describing whether to process or discard unrecognized or problematic
* original attributes when a class, record component, field, method or code is
* transformed in its exploded form.
* Default is {@code PASS_ALL_ATTRIBUTES} to process all original attributes.
* @see AttributeMapper.AttributeStability
*/
enum UnknownAttributesOption implements Option {
enum AttributesProcessingOption implements Option {
/** Process unknown attributes */
PASS_UNKNOWN_ATTRIBUTES,
/** Process all original attributes during transformation */
PASS_ALL_ATTRIBUTES,
/** Drop unknown attributes */
DROP_UNKNOWN_ATTRIBUTES
/** Drop unknown attributes during transformation */
DROP_UNKNOWN_ATTRIBUTES,
/** Drop unknown and unstable original attributes during transformation */
DROP_UNSTABLE_ATRIBUTES;
}
/**

View File

@ -52,6 +52,8 @@ public class AbstractDirectBuilder<M> {
}
public void writeAttribute(Attribute<?> a) {
attributes.withAttribute(a);
if (Util.isAttributeAllowed(a, context.attributesProcessingOption())) {
attributes.withAttribute(a);
}
}
}

View File

@ -51,7 +51,7 @@ class AnnotationReader {
annos[i] = readAnnotation(classReader, pos);
pos = skipAnnotation(classReader, pos);
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(annos);
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(annos);
}
public static AnnotationValue readElementValue(ClassReader classReader, int p) {
@ -78,7 +78,7 @@ class AnnotationReader {
values[i] = readElementValue(classReader, p);
p = skipElementValue(classReader, p);
}
yield new AnnotationImpl.OfArrayImpl(SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(values));
yield new AnnotationImpl.OfArrayImpl(SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(values));
}
default -> throw new IllegalArgumentException(
"Unexpected tag '%s' in AnnotationValue, pos = %d".formatted(tag, p - 1));
@ -93,7 +93,7 @@ class AnnotationReader {
annotations[i] = readTypeAnnotation(classReader, p, lc);
p = skipTypeAnnotation(classReader, p);
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(annotations);
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(annotations);
}
public static List<List<Annotation>> readParameterAnnotations(ClassReader classReader, int p) {
@ -103,7 +103,7 @@ class AnnotationReader {
pas[i] = readAnnotations(classReader, p);
p = skipAnnotations(classReader, p);
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(pas);
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(pas);
}
private static int skipElementValue(ClassReader classReader, int p) {
@ -156,7 +156,7 @@ class AnnotationReader {
annotationElements[i] = new AnnotationImpl.AnnotationElementImpl(elementName, value);
p = skipElementValue(classReader, p);
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(annotationElements);
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(annotationElements);
}
private static int skipElementValuePairs(ClassReader classReader, int p) {
@ -257,7 +257,7 @@ class AnnotationReader {
classReader.readU2(p + 4));
p += 6;
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(entries);
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
}
private static int skipTypeAnnotation(ClassReader classReader, int p) {

View File

@ -26,6 +26,7 @@
package jdk.internal.classfile.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@ -121,15 +122,16 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
for (int i = 0; p < end; i++, p += 2) {
entries[i] = classReader.readEntry(p);
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(entries);
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
}
public static List<Attribute<?>> readAttributes(AttributedElement enclosing, ClassReader reader, int pos,
Function<Utf8Entry, AttributeMapper<?>> customAttributes) {
int size = reader.readU2(pos);
var filled = new Object[size];
var filled = new ArrayList<Attribute<?>>(size);
int p = pos + 2;
int cfLen = reader.classfileLength();
var apo = ((ClassReaderImpl)reader).context().attributesProcessingOption();
for (int i = 0; i < size; ++i) {
Utf8Entry name = reader.readUtf8Entry(p);
int len = reader.readInt(p + 2);
@ -143,8 +145,8 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
mapper = customAttributes.apply(name);
}
if (mapper != null) {
filled[i] = mapper.readAttribute(enclosing, reader, p);
} else if (((ClassReaderImpl)reader).context().unknownAttributesOption() == Classfile.UnknownAttributesOption.PASS_UNKNOWN_ATTRIBUTES) {
filled.add((Attribute)mapper.readAttribute(enclosing, reader, p));
} else {
AttributeMapper<UnknownAttribute> fakeMapper = new AttributeMapper<>() {
@Override
public String name() {
@ -159,19 +161,27 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
@Override
public void writeAttribute(BufWriter buf, UnknownAttribute attr) {
throw new UnsupportedOperationException("Write of unknown attribute " + name() + " not supported");
buf.writeIndex(name);
var cont = attr.contents();
buf.writeInt(cont.length);
buf.writeBytes(cont);
}
@Override
public boolean allowMultiple() {
return true;
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeStability.UNKNOWN;
}
};
filled[i] = new BoundUnknownAttribute(reader, fakeMapper, p);
filled.add(new BoundUnknownAttribute(reader, fakeMapper, p));
}
p += len;
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(filled);
return Collections.unmodifiableList(filled);
}
public static final class BoundUnknownAttribute extends BoundAttribute<UnknownAttribute>
@ -179,35 +189,6 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
public BoundUnknownAttribute(ClassReader cf, AttributeMapper<UnknownAttribute> mapper, int pos) {
super(cf, mapper, pos);
}
@Override
public void writeTo(DirectClassBuilder builder) {
checkWriteSupported(builder::canWriteDirect);
super.writeTo(builder);
}
@Override
public void writeTo(DirectMethodBuilder builder) {
checkWriteSupported(builder::canWriteDirect);
super.writeTo(builder);
}
@Override
public void writeTo(DirectFieldBuilder builder) {
checkWriteSupported(builder::canWriteDirect);
super.writeTo(builder);
}
@Override
public void writeTo(BufWriter buf) {
checkWriteSupported(buf::canWriteDirect);
super.writeTo(buf);
}
private void checkWriteSupported(Function<ConstantPool, Boolean> condition) {
if (!condition.apply(classReader))
throw new UnsupportedOperationException("Write of unknown attribute " + attributeName() + " not supported to alien constant pool");
}
}
public static final class BoundStackMapTableAttribute

View File

@ -138,7 +138,7 @@ public final class ClassImpl
arr[i] = reader.readClassEntry(pos);
pos += 2;
}
this.interfaces = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(arr);
this.interfaces = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(arr);
}
return interfaces;
}

View File

@ -43,7 +43,7 @@ import jdk.internal.classfile.constantpool.Utf8Entry;
public record ClassfileImpl(StackMapsOption stackMapsOption,
DebugElementsOption debugElementsOption,
LineNumbersOption lineNumbersOption,
UnknownAttributesOption unknownAttributesOption,
AttributesProcessingOption attributesProcessingOption,
ConstantPoolSharingOption constantPoolSharingOption,
ShortJumpsOption shortJumpsOption,
DeadCodeOption deadCodeOption,
@ -55,7 +55,7 @@ public record ClassfileImpl(StackMapsOption stackMapsOption,
StackMapsOption.STACK_MAPS_WHEN_REQUIRED,
DebugElementsOption.PASS_DEBUG,
LineNumbersOption.PASS_LINE_NUMBERS,
UnknownAttributesOption.PASS_UNKNOWN_ATTRIBUTES,
AttributesProcessingOption.PASS_ALL_ATTRIBUTES,
ConstantPoolSharingOption.SHARED_POOL,
ShortJumpsOption.FIX_SHORT_JUMPS,
DeadCodeOption.PATCH_DEAD_CODE,
@ -74,7 +74,7 @@ public record ClassfileImpl(StackMapsOption stackMapsOption,
var smo = stackMapsOption;
var deo = debugElementsOption;
var lno = lineNumbersOption;
var uao = unknownAttributesOption;
var apo = attributesProcessingOption;
var cpso = constantPoolSharingOption;
var sjo = shortJumpsOption;
var dco = deadCodeOption;
@ -86,7 +86,7 @@ public record ClassfileImpl(StackMapsOption stackMapsOption,
case StackMapsOption oo -> smo = oo;
case DebugElementsOption oo -> deo = oo;
case LineNumbersOption oo -> lno = oo;
case UnknownAttributesOption oo -> uao = oo;
case AttributesProcessingOption oo -> apo = oo;
case ConstantPoolSharingOption oo -> cpso = oo;
case ShortJumpsOption oo -> sjo = oo;
case DeadCodeOption oo -> dco = oo;
@ -95,7 +95,7 @@ public record ClassfileImpl(StackMapsOption stackMapsOption,
case AttributeMapperOption oo -> amo = oo;
}
}
return new ClassfileImpl(smo, deo, lno, uao, cpso, sjo, dco, dlo, chro, amo);
return new ClassfileImpl(smo, deo, lno, apo, cpso, sjo, dco, dlo, chro, amo);
}
@Override

View File

@ -27,9 +27,7 @@ package jdk.internal.classfile.impl;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.util.AbstractList;
import java.util.BitSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
@ -38,11 +36,13 @@ import jdk.internal.classfile.constantpool.ClassEntry;
import jdk.internal.classfile.constantpool.ModuleEntry;
import jdk.internal.classfile.constantpool.NameAndTypeEntry;
import java.lang.constant.ModuleDesc;
import jdk.internal.classfile.impl.TemporaryConstantPool;
import java.lang.reflect.AccessFlag;
import static jdk.internal.classfile.Classfile.ACC_STATIC;
import jdk.internal.access.SharedSecrets;
import jdk.internal.classfile.Attribute;
import jdk.internal.classfile.AttributeMapper;
import jdk.internal.classfile.Classfile;
/**
* Helper to create and manipulate type descriptors, where type descriptors are
@ -54,6 +54,15 @@ public class Util {
private Util() {
}
private static final int ATTRIBUTE_STABILITY_COUNT = AttributeMapper.AttributeStability.values().length;
public static boolean isAttributeAllowed(final Attribute<?> attr,
final Classfile.AttributesProcessingOption processingOption) {
return attr instanceof BoundAttribute
? ATTRIBUTE_STABILITY_COUNT - attr.attributeMapper().stability().ordinal() > processingOption.ordinal()
: true;
}
public static int parameterSlots(MethodTypeDesc mDesc) {
int count = 0;
for (int i = 0; i < mDesc.parameterCount(); i++) {
@ -121,7 +130,7 @@ public class Util {
for (int i = 0; i < result.length; i++) {
result[i] = TemporaryConstantPool.INSTANCE.classEntry(list.get(i));
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(result);
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
}
public static List<ModuleEntry> moduleEntryList(List<? extends ModuleDesc> list) {
@ -129,7 +138,7 @@ public class Util {
for (int i = 0; i < result.length; i++) {
result[i] = TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(list.get(i).name()));
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(result);
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
}
public static void checkKind(Opcode op, Opcode.Kind k) {

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Testing Classfile options on small Corpus.
* @run junit/othervm -Djunit.jupiter.execution.parallel.enabled=true OptionsTest
*/
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException;
import java.lang.constant.ClassDesc;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import jdk.internal.classfile.AttributeMapper;
import jdk.internal.classfile.AttributedElement;
import jdk.internal.classfile.BufWriter;
import jdk.internal.classfile.ClassReader;
import jdk.internal.classfile.ClassTransform;
import jdk.internal.classfile.Classfile;
import jdk.internal.classfile.ClassfileElement;
import jdk.internal.classfile.CodeTransform;
import jdk.internal.classfile.CompoundElement;
import jdk.internal.classfile.CustomAttribute;
/**
* OptionsTest
*/
@Execution(ExecutionMode.CONCURRENT)
class OptionsTest {
protected static final FileSystem JRT = FileSystems.getFileSystem(URI.create("jrt:/"));
static Path[] corpus() throws IOException, URISyntaxException {
return Files.walk(JRT.getPath("modules/java.base/java/util"))
.filter(p -> Files.isRegularFile(p) && p.toString().endsWith(".class"))
.toArray(Path[]::new);
}
@ParameterizedTest
@MethodSource("corpus")
void testAttributesProcessingOptionOnTransform(Path path) throws Exception {
testNoUnstable(path, Classfile.of().parse(
Classfile.of(Classfile.AttributesProcessingOption.DROP_UNSTABLE_ATRIBUTES).transform(
Classfile.of().parse(path),
ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL))));
}
static class StrangeAttribute extends CustomAttribute<StrangeAttribute> {
public StrangeAttribute() {
super(STRANGE_ATTRIBUTE_MAPPER);
}
}
static final AttributeMapper<StrangeAttribute> STRANGE_ATTRIBUTE_MAPPER = new AttributeMapper<>() {
@Override
public String name() {
return "StrangeAttribute";
}
@Override
public StrangeAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) {
return new StrangeAttribute();
}
@Override
public void writeAttribute(BufWriter buf, StrangeAttribute attr) {
buf.writeIndex(buf.constantPool().utf8Entry(name()));
buf.writeInt(0);
}
@Override
public AttributeMapper.AttributeStability stability() {
return AttributeMapper.AttributeStability.STATELESS;
}
};
@Test
void testUnknownAttribute() throws Exception {
var classBytes = Classfile.of(Classfile.AttributeMapperOption.of(e -> {
return e.equalsString(STRANGE_ATTRIBUTE_MAPPER.name()) ? STRANGE_ATTRIBUTE_MAPPER : null;
})).build(ClassDesc.of("StrangeClass"), clb -> clb.with(new StrangeAttribute()));
//test default
assertFalse(Classfile.of().parse(classBytes).attributes().isEmpty());
//test drop unknown at transform
assertTrue(Classfile.of().parse(
Classfile.of(Classfile.AttributesProcessingOption.DROP_UNKNOWN_ATTRIBUTES).transform(
Classfile.of().parse(classBytes),
ClassTransform.ACCEPT_ALL)).attributes().isEmpty());
}
void testNoUnstable(Path path, ClassfileElement e) {
if (e instanceof AttributedElement ae) ae.attributes().forEach(a ->
assertTrue(AttributeMapper.AttributeStability.UNSTABLE.ordinal() >= a.attributeMapper().stability().ordinal(),
() -> "class " + path + " contains unexpected " + a));
if (e instanceof CompoundElement ce) ce.forEachElement(ee -> testNoUnstable(path, (ClassfileElement)ee));
}
}