8361635: Missing List length validation in the Class-File API

Reviewed-by: asotona
This commit is contained in:
Chen Liang 2025-09-03 19:21:38 +00:00
parent 8d236615b7
commit 431f467246
48 changed files with 866 additions and 111 deletions

View File

@ -95,6 +95,8 @@ public sealed interface Annotation
* @param annotationClass the constant pool entry holding the descriptor string
* of the annotation interface
* @param elements the element-value pairs of the annotation
* @throws IllegalArgumentException if the number of pairs exceeds the limit
* of {@link java.lang.classfile##u2 u2}
*/
static Annotation of(Utf8Entry annotationClass,
List<AnnotationElement> elements) {
@ -106,6 +108,8 @@ public sealed interface Annotation
* @param annotationClass the constant pool entry holding the descriptor string
* of the annotation interface
* @param elements the element-value pairs of the annotation
* @throws IllegalArgumentException if the number of pairs exceeds the limit
* of {@link java.lang.classfile##u2 u2}
*/
static Annotation of(Utf8Entry annotationClass,
AnnotationElement... elements) {
@ -116,6 +120,8 @@ public sealed interface Annotation
* {@return an annotation}
* @param annotationClass the descriptor of the annotation interface
* @param elements the element-value pairs of the annotation
* @throws IllegalArgumentException if the number of pairs exceeds the limit
* of {@link java.lang.classfile##u2 u2}
*/
static Annotation of(ClassDesc annotationClass,
List<AnnotationElement> elements) {
@ -126,6 +132,8 @@ public sealed interface Annotation
* {@return an annotation}
* @param annotationClass the descriptor of the annotation interface
* @param elements the element-value pairs of the annotation
* @throws IllegalArgumentException if the number of pairs exceeds the limit
* of {@link java.lang.classfile##u2 u2}
*/
static Annotation of(ClassDesc annotationClass,
AnnotationElement... elements) {

View File

@ -209,6 +209,8 @@ public sealed interface AnnotationElement
* @param name the name of the key
* @param values the associated values
* @see AnnotationValue#ofArray(AnnotationValue...) AnnotationValue::ofArray
* @throws IllegalArgumentException if the number of associated values
* exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static AnnotationElement ofArray(String name,
AnnotationValue... values) {

View File

@ -673,6 +673,8 @@ public sealed interface AnnotationValue {
* on array values derived from Java source code.
*
* @param values the array elements
* @throws IllegalArgumentException if the length of array exceeds the limit
* of {@link java.lang.classfile##u2 u2}
*/
static OfArray ofArray(List<AnnotationValue> values) {
return new AnnotationImpl.OfArrayImpl(values);
@ -686,6 +688,8 @@ public sealed interface AnnotationValue {
* on array values derived from Java source code.
*
* @param values the array elements
* @throws IllegalArgumentException if the length of array exceeds the limit
* of {@link java.lang.classfile##u2 u2}
*/
static OfArray ofArray(AnnotationValue... values) {
return ofArray(List.of(values));
@ -699,7 +703,8 @@ public sealed interface AnnotationValue {
* @param value the annotation value
* @throws IllegalArgumentException when the {@code value} parameter is not
* a primitive, a wrapper of primitive, a String, a ClassDesc,
* an enum constant, or an array of one of these.
* an enum constant, or an array of one of these; or any array has
* length over the limit of {@link java.lang.classfile##u2 u2}
*/
static AnnotationValue of(Object value) {
if (value instanceof String s) {

View File

@ -131,6 +131,8 @@ public sealed interface ClassBuilder
*
* @param interfaces the interfaces
* @return this builder
* @throws IllegalArgumentException if the number of interfaces exceeds the
* limit of {@link java.lang.classfile##u2 u2}
* @see Interfaces
*/
default ClassBuilder withInterfaces(List<ClassEntry> interfaces) {
@ -142,6 +144,8 @@ public sealed interface ClassBuilder
*
* @param interfaces the interfaces
* @return this builder
* @throws IllegalArgumentException if the number of interfaces exceeds the
* limit of {@link java.lang.classfile##u2 u2}
* @see Interfaces
*/
default ClassBuilder withInterfaces(ClassEntry... interfaces) {
@ -153,7 +157,9 @@ public sealed interface ClassBuilder
*
* @param interfaces the interfaces
* @return this builder
* @throws IllegalArgumentException if any element of {@code interfaces} is primitive
* @throws IllegalArgumentException if any of {@code interfaces} is primitive,
* or if the number of interfaces exceeds the limit of {@link
* java.lang.classfile##u2 u2}
* @see Interfaces
*/
default ClassBuilder withInterfaceSymbols(List<ClassDesc> interfaces) {
@ -165,7 +171,9 @@ public sealed interface ClassBuilder
*
* @param interfaces the interfaces
* @return this builder
* @throws IllegalArgumentException if any element of {@code interfaces} is primitive
* @throws IllegalArgumentException if any of {@code interfaces} is primitive,
* or if the number of interfaces exceeds the limit of {@link
* java.lang.classfile##u2 u2}
* @see Interfaces
*/
default ClassBuilder withInterfaceSymbols(ClassDesc... interfaces) {

View File

@ -2402,8 +2402,8 @@ public sealed interface CodeBuilder
* variable by a constant.
* <p>
* This may also generate {@link Opcode#IINC_W wide iinc} instructions if
* {@code slot} exceeds {@code 255} or {@code val} exceeds the range of
* {@link TypeKind#BYTE byte}.
* {@code slot} exceeds the limit of {@link java.lang.classfile##u1 u1} or
* {@code val} exceeds the range of {@link TypeKind#BYTE byte}.
*
* @param slot the local variable slot
* @param val the increment value

View File

@ -54,6 +54,8 @@ public sealed interface Interfaces
/**
* {@return an {@linkplain Interfaces} element}
* @param interfaces the interfaces
* @throws IllegalArgumentException if the number of interfaces
* exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static Interfaces of(List<ClassEntry> interfaces) {
return new InterfacesImpl(interfaces);
@ -62,6 +64,8 @@ public sealed interface Interfaces
/**
* {@return an {@linkplain Interfaces} element}
* @param interfaces the interfaces
* @throws IllegalArgumentException if the number of interfaces
* exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static Interfaces of(ClassEntry... interfaces) {
return of(List.of(interfaces));
@ -70,7 +74,9 @@ public sealed interface Interfaces
/**
* {@return an {@linkplain Interfaces} element}
* @param interfaces the interfaces
* @throws IllegalArgumentException if any of {@code interfaces} is primitive
* @throws IllegalArgumentException if any of {@code interfaces} is primitive,
* or if the number of interfaces exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static Interfaces ofSymbols(List<ClassDesc> interfaces) {
return of(Util.entryList(interfaces));
@ -79,7 +85,9 @@ public sealed interface Interfaces
/**
* {@return an {@linkplain Interfaces} element}
* @param interfaces the interfaces
* @throws IllegalArgumentException if any of {@code interfaces} is primitive
* @throws IllegalArgumentException if any of {@code interfaces} is primitive,
* or if the number of interfaces exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static Interfaces ofSymbols(ClassDesc... interfaces) {
return ofSymbols(Arrays.asList(interfaces));

View File

@ -182,6 +182,8 @@ public sealed interface TypeAnnotation
* @param targetInfo which type in a declaration or expression is annotated
* @param targetPath which part of the type is annotated
* @param annotation the annotation
* @throws IllegalArgumentException if the size of {@code targetPath}
* exceeds the limit of {@link java.lang.classfile##u1 u1}
*/
static TypeAnnotation of(TargetInfo targetInfo, List<TypePathComponent> targetPath,
Annotation annotation) {
@ -486,6 +488,8 @@ public sealed interface TypeAnnotation
* including a variable declared as a resource in a try-with-resources statement}
* @param targetType {@link TargetType#LOCAL_VARIABLE} or {@link TargetType#RESOURCE_VARIABLE}
* @param table the list of local variable targets
* @throws IllegalArgumentException if the size of the list of targets
* exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static LocalVarTarget ofVariable(TargetType targetType, List<LocalVarTargetInfo> table) {
return new TargetInfoImpl.LocalVarTargetImpl(targetType, table);
@ -494,6 +498,8 @@ public sealed interface TypeAnnotation
/**
* {@return a target for annotations on the type in a local variable declaration}
* @param table the list of local variable targets
* @throws IllegalArgumentException if the size of the list of targets
* exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static LocalVarTarget ofLocalVariable(List<LocalVarTargetInfo> table) {
return ofVariable(TargetType.LOCAL_VARIABLE, table);
@ -503,6 +509,8 @@ public sealed interface TypeAnnotation
* {@return a target for annotations on the type in a local variable declared
* as a resource in a try-with-resources statement}
* @param table the list of local variable targets
* @throws IllegalArgumentException if the size of the list of targets
* exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static LocalVarTarget ofResourceVariable(List<LocalVarTargetInfo> table) {
return ofVariable(TargetType.RESOURCE_VARIABLE, table);
@ -802,7 +810,6 @@ public sealed interface TypeAnnotation
*/
Label startLabel();
/**
* The given local variable has a value at indices into the code array in the interval
* [start_pc, start_pc + length), that is, between start_pc inclusive and start_pc + length exclusive.

View File

@ -88,6 +88,8 @@ public sealed interface CharacterRangeTableAttribute
* {@link CodeBuilder#characterRange CodeBuilder::characterRange} instead.
*
* @param ranges the descriptions of the character ranges
* @throws IllegalArgumentException if the number of ranges exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static CharacterRangeTableAttribute of(List<CharacterRangeInfo> ranges) {
return new UnboundAttribute.UnboundCharacterRangeTableAttribute(ranges);

View File

@ -77,6 +77,8 @@ public sealed interface ExceptionsAttribute
/**
* {@return an {@code Exceptions} attribute}
* @param exceptions the exceptions that may be thrown from this method
* @throws IllegalArgumentException if the number of exceptions exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static ExceptionsAttribute of(List<ClassEntry> exceptions) {
return new UnboundAttribute.UnboundExceptionsAttribute(exceptions);
@ -85,6 +87,8 @@ public sealed interface ExceptionsAttribute
/**
* {@return an {@code Exceptions} attribute}
* @param exceptions the exceptions that may be thrown from this method
* @throws IllegalArgumentException if the number of exceptions exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static ExceptionsAttribute of(ClassEntry... exceptions) {
return of(List.of(exceptions));
@ -93,6 +97,8 @@ public sealed interface ExceptionsAttribute
/**
* {@return an {@code Exceptions} attribute}
* @param exceptions the exceptions that may be thrown from this method
* @throws IllegalArgumentException if the number of exceptions exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static ExceptionsAttribute ofSymbols(List<ClassDesc> exceptions) {
return of(Util.entryList(exceptions));
@ -101,6 +107,8 @@ public sealed interface ExceptionsAttribute
/**
* {@return an {@code Exceptions} attribute}
* @param exceptions the exceptions that may be thrown from this method
* @throws IllegalArgumentException if the number of exceptions exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static ExceptionsAttribute ofSymbols(ClassDesc... exceptions) {
return ofSymbols(Arrays.asList(exceptions));

View File

@ -65,6 +65,8 @@ public sealed interface InnerClassesAttribute
/**
* {@return an {@code InnerClasses} attribute}
* @param innerClasses descriptions of the nested classes
* @throws IllegalArgumentException if the number of descriptions exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static InnerClassesAttribute of(List<InnerClassInfo> innerClasses) {
return new UnboundAttribute.UnboundInnerClassesAttribute(innerClasses);
@ -73,6 +75,8 @@ public sealed interface InnerClassesAttribute
/**
* {@return an {@code InnerClasses} attribute}
* @param innerClasses descriptions of the nested classes
* @throws IllegalArgumentException if the number of descriptions exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static InnerClassesAttribute of(InnerClassInfo... innerClasses) {
return new UnboundAttribute.UnboundInnerClassesAttribute(List.of(innerClasses));

View File

@ -79,6 +79,8 @@ public sealed interface LineNumberTableAttribute
* order instead.
*
* @param lines the line number descriptions
* @throws IllegalArgumentException if the number of descriptions exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static LineNumberTableAttribute of(List<LineNumberInfo> lines) {
return new UnboundAttribute.UnboundLineNumberTableAttribute(lines);

View File

@ -83,6 +83,8 @@ public sealed interface LocalVariableTableAttribute
* {@link CodeBuilder#localVariable CodeBuilder::localVariable} instead.
*
* @param locals the local variable descriptions
* @throws IllegalArgumentException if the number of descriptions exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static LocalVariableTableAttribute of(List<LocalVariableInfo> locals) {
return new UnboundAttribute.UnboundLocalVariableTableAttribute(locals);

View File

@ -79,6 +79,8 @@ public sealed interface LocalVariableTypeTableAttribute
/**
* {@return a {@code LocalVariableTypeTable} attribute}
* @param locals the local variable descriptions
* @throws IllegalArgumentException if the number of descriptions exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static LocalVariableTypeTableAttribute of(List<LocalVariableTypeInfo> locals) {
return new UnboundAttribute.UnboundLocalVariableTypeTableAttribute(locals);

View File

@ -68,6 +68,8 @@ public sealed interface MethodParametersAttribute
/**
* {@return a {@code MethodParameters} attribute}
* @param parameters the method parameter descriptions
* @throws IllegalArgumentException if the number of parameters exceeds the
* limit of {@link java.lang.classfile##u1 u1}
*/
static MethodParametersAttribute of(List<MethodParameterInfo> parameters) {
return new UnboundAttribute.UnboundMethodParametersAttribute(parameters);
@ -76,6 +78,8 @@ public sealed interface MethodParametersAttribute
/**
* {@return a {@code MethodParameters} attribute}
* @param parameters the method parameter descriptions
* @throws IllegalArgumentException if the number of parameters exceeds the
* limit of {@link java.lang.classfile##u1 u1}
*/
static MethodParametersAttribute of(MethodParameterInfo... parameters) {
return of(List.of(parameters));

View File

@ -171,7 +171,8 @@ public sealed interface ModuleAttribute
* @param uses the consumed services
* @param provides the provided services
* @throws IllegalArgumentException if {@code moduleFlags} is not {@link
* java.lang.classfile##u2 u2}
* java.lang.classfile##u2 u2} or any of the collections has a size
* over the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleAttribute of(ModuleEntry moduleName, int moduleFlags,
Utf8Entry moduleVersion,
@ -188,6 +189,9 @@ public sealed interface ModuleAttribute
*
* @param moduleName the module name
* @param attrHandler a handler that receives a {@link ModuleAttributeBuilder}
* @throws IllegalArgumentException if the information from the handler exceeds
* the {@code class} file format limit, such as a list with size
* over the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleAttribute of(ModuleDesc moduleName,
Consumer<ModuleAttributeBuilder> attrHandler) {
@ -296,6 +300,8 @@ public sealed interface ModuleAttribute
* @param exportsFlagsMask the export flags
* @param exportsToModules the modules to export to, or empty for an unqualified export
* @return this builder
* @throws IllegalArgumentException if the number of modules exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
ModuleAttributeBuilder exports(PackageDesc pkge, int exportsFlagsMask, ModuleDesc... exportsToModules);
@ -307,7 +313,9 @@ public sealed interface ModuleAttribute
* @param exportsToModules the modules to export to, or empty for an unqualified export
* @return this builder
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_EXPORTS} location
* {@link AccessFlag.Location#MODULE_EXPORTS} location or the
* number of modules exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
default ModuleAttributeBuilder exports(PackageDesc pkge, Collection<AccessFlag> exportsFlags, ModuleDesc... exportsToModules) {
return exports(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportsFlags), exportsToModules);
@ -333,6 +341,8 @@ public sealed interface ModuleAttribute
* @param opensFlagsMask the open package flags
* @param opensToModules the modules to open to, or empty for an unqualified open
* @return this builder
* @throws IllegalArgumentException if the number of modules exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
ModuleAttributeBuilder opens(PackageDesc pkge, int opensFlagsMask, ModuleDesc... opensToModules);
@ -349,7 +359,9 @@ public sealed interface ModuleAttribute
* @param opensToModules the modules to open to, or empty for an unqualified open
* @return this builder
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_OPENS} location
* {@link AccessFlag.Location#MODULE_OPENS} location, or if the
* number of modules exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
default ModuleAttributeBuilder opens(PackageDesc pkge, Collection<AccessFlag> opensFlags, ModuleDesc... opensToModules) {
return opens(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensToModules);
@ -391,7 +403,10 @@ public sealed interface ModuleAttribute
* @param service the service class provided
* @param implClasses the implementation classes
* @return this builder
* @throws IllegalArgumentException if {@code service} or any of the {@code implClasses} represents a primitive type
* @throws IllegalArgumentException if {@code service} or any of the
* {@code implClasses} represents a primitive type, or the
* number of implementations exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
ModuleAttributeBuilder provides(ClassDesc service, ClassDesc... implClasses);

View File

@ -104,7 +104,8 @@ public sealed interface ModuleExportInfo
* @param exportsTo the modules to which this package is exported, or empty
* if this is an unqualified export
* @throws IllegalArgumentException if {@code exportFlags} is not {@link
* java.lang.classfile##u2 u2}
* java.lang.classfile##u2 u2} or if the number of modules exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleExportInfo of(PackageEntry exports, int exportFlags,
List<ModuleEntry> exportsTo) {
@ -119,7 +120,9 @@ public sealed interface ModuleExportInfo
* @param exportsTo the modules to which this package is exported, or empty
* if this is an unqualified export
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_EXPORTS} location
* {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the
* number of modules exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static ModuleExportInfo of(PackageEntry exports, Collection<AccessFlag> exportFlags,
List<ModuleEntry> exportsTo) {
@ -134,7 +137,8 @@ public sealed interface ModuleExportInfo
* @param exportsTo the modules to which this package is exported, or empty
* if this is an unqualified export
* @throws IllegalArgumentException if {@code exportFlags} is not {@link
* java.lang.classfile##u2 u2}
* java.lang.classfile##u2 u2} or if the number of modules exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleExportInfo of(PackageEntry exports,
int exportFlags,
@ -150,7 +154,9 @@ public sealed interface ModuleExportInfo
* @param exportsTo the modules to which this package is exported, or empty
* if this is an unqualified export
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_EXPORTS} location
* {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the
* number of modules exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static ModuleExportInfo of(PackageEntry exports,
Collection<AccessFlag> exportFlags,
@ -166,7 +172,8 @@ public sealed interface ModuleExportInfo
* @param exportsTo the modules to which this package is exported, or empty
* if this is an unqualified export
* @throws IllegalArgumentException if {@code exportFlags} is not {@link
* java.lang.classfile##u2 u2}
* java.lang.classfile##u2 u2} or if the number of modules exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleExportInfo of(PackageDesc exports, int exportFlags,
List<ModuleDesc> exportsTo) {
@ -183,7 +190,9 @@ public sealed interface ModuleExportInfo
* @param exportsTo the modules to which this package is exported, or empty
* if this is an unqualified export
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_EXPORTS} location
* {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the
* number of modules exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static ModuleExportInfo of(PackageDesc exports, Collection<AccessFlag> exportFlags,
List<ModuleDesc> exportsTo) {
@ -198,7 +207,8 @@ public sealed interface ModuleExportInfo
* @param exportsTo the modules to which this package is exported, or empty
* if this is an unqualified export
* @throws IllegalArgumentException if {@code exportFlags} is not {@link
* java.lang.classfile##u2 u2}
* java.lang.classfile##u2 u2} or if the number of modules exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleExportInfo of(PackageDesc exports,
int exportFlags,
@ -214,7 +224,9 @@ public sealed interface ModuleExportInfo
* @param exportsTo the modules to which this package is exported, or empty
* if this is an unqualified export
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_EXPORTS} location
* {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the
* number of modules exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static ModuleExportInfo of(PackageDesc exports,
Collection<AccessFlag> exportFlags,

View File

@ -96,6 +96,8 @@ public sealed interface ModuleHashesAttribute
* {@return a {@code ModuleHashes} attribute}
* @param algorithm the hashing algorithm
* @param hashes the hash descriptions
* @throws IllegalArgumentException if the number of descriptions exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleHashesAttribute of(String algorithm,
List<ModuleHashInfo> hashes) {
@ -106,6 +108,8 @@ public sealed interface ModuleHashesAttribute
* {@return a {@code ModuleHashes} attribute}
* @param algorithm the hashing algorithm
* @param hashes the hash descriptions
* @throws IllegalArgumentException if the number of descriptions exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleHashesAttribute of(String algorithm,
ModuleHashInfo... hashes) {
@ -116,6 +120,8 @@ public sealed interface ModuleHashesAttribute
* {@return a {@code ModuleHashes} attribute}
* @param algorithm the hashing algorithm
* @param hashes the hash descriptions
* @throws IllegalArgumentException if the number of descriptions exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleHashesAttribute of(Utf8Entry algorithm,
List<ModuleHashInfo> hashes) {
@ -126,6 +132,8 @@ public sealed interface ModuleHashesAttribute
* {@return a {@code ModuleHashes} attribute}
* @param algorithm the hashing algorithm
* @param hashes the hash descriptions
* @throws IllegalArgumentException if the number of descriptions exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleHashesAttribute of(Utf8Entry algorithm,
ModuleHashInfo... hashes) {

View File

@ -110,7 +110,8 @@ public sealed interface ModuleOpenInfo
* @param opensTo the modules to which this package is opened, or empty if
* this is an unqualified open
* @throws IllegalArgumentException if {@code opensFlags} is not {@link
* java.lang.classfile##u2 u2}
* java.lang.classfile##u2 u2} or if the number of modules exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleOpenInfo of(PackageEntry opens, int opensFlags,
List<ModuleEntry> opensTo) {
@ -125,7 +126,8 @@ public sealed interface ModuleOpenInfo
* @param opensTo the modules to which this package is opened, or empty if
* this is an unqualified open
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_OPENS} location
* {@link AccessFlag.Location#MODULE_OPENS} location, or the number
* of modules exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleOpenInfo of(PackageEntry opens, Collection<AccessFlag> opensFlags,
List<ModuleEntry> opensTo) {
@ -140,7 +142,8 @@ public sealed interface ModuleOpenInfo
* @param opensTo the modules to which this package is opened, or empty if
* this is an unqualified open
* @throws IllegalArgumentException if {@code opensFlags} is not {@link
* java.lang.classfile##u2 u2}
* java.lang.classfile##u2 u2} or if the number of modules exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleOpenInfo of(PackageEntry opens,
int opensFlags,
@ -156,7 +159,8 @@ public sealed interface ModuleOpenInfo
* @param opensTo the modules to which this package is opened, or empty if
* this is an unqualified open
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_OPENS} location
* {@link AccessFlag.Location#MODULE_OPENS} location, or the number
* of modules exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleOpenInfo of(PackageEntry opens,
Collection<AccessFlag> opensFlags,
@ -171,7 +175,8 @@ public sealed interface ModuleOpenInfo
* @param opensTo the modules to which this package is opened, if it is a
* qualified open, or empty
* @throws IllegalArgumentException if {@code opensFlags} is not {@link
* java.lang.classfile##u2 u2}
* java.lang.classfile##u2 u2} or if the number of modules exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleOpenInfo of(PackageDesc opens, int opensFlags,
List<ModuleDesc> opensTo) {
@ -187,7 +192,8 @@ public sealed interface ModuleOpenInfo
* @param opensTo the modules to which this package is opened, if it is a
* qualified open, or empty
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_OPENS} location
* {@link AccessFlag.Location#MODULE_OPENS} location, or the number
* of modules exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleOpenInfo of(PackageDesc opens, Collection<AccessFlag> opensFlags,
List<ModuleDesc> opensTo) {
@ -201,7 +207,8 @@ public sealed interface ModuleOpenInfo
* @param opensTo the packages to which this package is opened, or empty if
* this is an unqualified open
* @throws IllegalArgumentException if {@code opensFlags} is not {@link
* java.lang.classfile##u2 u2}
* java.lang.classfile##u2 u2} or if the number of modules exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleOpenInfo of(PackageDesc opens,
int opensFlags,
@ -216,7 +223,8 @@ public sealed interface ModuleOpenInfo
* @param opensTo the packages to which this package is opened, or empty if
* this is an unqualified open
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#MODULE_OPENS} location
* {@link AccessFlag.Location#MODULE_OPENS} location, or the number
* of modules exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleOpenInfo of(PackageDesc opens,
Collection<AccessFlag> opensFlags,

View File

@ -74,6 +74,8 @@ public sealed interface ModulePackagesAttribute
/**
* {@return a {@code ModulePackages} attribute}
* @param packages the packages
* @throws IllegalArgumentException if the number of packages exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static ModulePackagesAttribute of(List<PackageEntry> packages) {
return new UnboundAttribute.UnboundModulePackagesAttribute(packages);
@ -82,6 +84,8 @@ public sealed interface ModulePackagesAttribute
/**
* {@return a {@code ModulePackages} attribute}
* @param packages the packages
* @throws IllegalArgumentException if the number of packages exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static ModulePackagesAttribute of(PackageEntry... packages) {
return of(List.of(packages));
@ -90,6 +94,8 @@ public sealed interface ModulePackagesAttribute
/**
* {@return a {@code ModulePackages} attribute}
* @param packages the packages
* @throws IllegalArgumentException if the number of packages exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static ModulePackagesAttribute ofNames(List<PackageDesc> packages) {
var p = new PackageEntry[packages.size()];
@ -102,6 +108,8 @@ public sealed interface ModulePackagesAttribute
/**
* {@return a {@code ModulePackages} attribute}
* @param packages the packages
* @throws IllegalArgumentException if the number of packages exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static ModulePackagesAttribute ofNames(PackageDesc... packages) {
// List view, since ref to packages is temporary

View File

@ -64,6 +64,8 @@ public sealed interface ModuleProvideInfo
* {@return a service provision description}
* @param provides the service class interface
* @param providesWith the service class implementations, must not be empty
* @throws IllegalArgumentException if the number of implementations exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleProvideInfo of(ClassEntry provides,
List<ClassEntry> providesWith) {
@ -74,6 +76,8 @@ public sealed interface ModuleProvideInfo
* {@return a service provision description}
* @param provides the service class interface
* @param providesWith the service class implementations, must not be empty
* @throws IllegalArgumentException if the number of implementations exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleProvideInfo of(ClassEntry provides,
ClassEntry... providesWith) {
@ -85,7 +89,8 @@ public sealed interface ModuleProvideInfo
* @param provides the service class interface
* @param providesWith the service class implementations, must not be empty
* @throws IllegalArgumentException if {@code provides} or any of {@code
* providesWith} represents a primitive type
* providesWith} represents a primitive type, or the number of
* implementations exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleProvideInfo of(ClassDesc provides,
List<ClassDesc> providesWith) {
@ -97,7 +102,8 @@ public sealed interface ModuleProvideInfo
* @param provides the service class interface
* @param providesWith the service class implementations, must not be empty
* @throws IllegalArgumentException if {@code provides} or any of {@code
* providesWith} represents a primitive type
* providesWith} represents a primitive type, or the number of
* implementations exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static ModuleProvideInfo of(ClassDesc provides,
ClassDesc... providesWith) {

View File

@ -72,6 +72,8 @@ public sealed interface NestMembersAttribute extends Attribute<NestMembersAttrib
* {@return a {@code NestMembers} attribute}
*
* @param nestMembers the member classes of the nest
* @throws IllegalArgumentException if the number of member classes exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static NestMembersAttribute of(List<ClassEntry> nestMembers) {
return new UnboundAttribute.UnboundNestMembersAttribute(nestMembers);
@ -81,6 +83,8 @@ public sealed interface NestMembersAttribute extends Attribute<NestMembersAttrib
* {@return a {@code NestMembers} attribute}
*
* @param nestMembers the member classes of the nest
* @throws IllegalArgumentException if the number of member classes exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static NestMembersAttribute of(ClassEntry... nestMembers) {
return of(List.of(nestMembers));
@ -90,7 +94,9 @@ public sealed interface NestMembersAttribute extends Attribute<NestMembersAttrib
* {@return a {@code NestMembers} attribute}
*
* @param nestMembers the member classes of the nest
* @throws IllegalArgumentException if any of {@code nestMembers} is primitive
* @throws IllegalArgumentException if any of {@code nestMembers} is primitive,
* or if the number of member classes exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static NestMembersAttribute ofSymbols(List<ClassDesc> nestMembers) {
return of(Util.entryList(nestMembers));
@ -100,7 +106,9 @@ public sealed interface NestMembersAttribute extends Attribute<NestMembersAttrib
* {@return a {@code NestMembers} attribute}
*
* @param nestMembers the member classes of the nest
* @throws IllegalArgumentException if any of {@code nestMembers} is primitive
* @throws IllegalArgumentException if any of {@code nestMembers} is primitive,
* or if the number of member classes exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static NestMembersAttribute ofSymbols(ClassDesc... nestMembers) {
// List version does defensive copy

View File

@ -77,6 +77,8 @@ public sealed interface PermittedSubclassesAttribute
* {@return a {@code PermittedSubclasses} attribute}
*
* @param permittedSubclasses the permitted subclasses or subinterfaces
* @throws IllegalArgumentException if the number of permitted subclasses
* or subinterfaces exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static PermittedSubclassesAttribute of(List<ClassEntry> permittedSubclasses) {
return new UnboundAttribute.UnboundPermittedSubclassesAttribute(permittedSubclasses);
@ -86,6 +88,8 @@ public sealed interface PermittedSubclassesAttribute
* {@return a {@code PermittedSubclasses} attribute}
*
* @param permittedSubclasses the permitted subclasses or subinterfaces
* @throws IllegalArgumentException if the number of permitted subclasses
* or subinterfaces exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static PermittedSubclassesAttribute of(ClassEntry... permittedSubclasses) {
return of(List.of(permittedSubclasses));
@ -95,7 +99,9 @@ public sealed interface PermittedSubclassesAttribute
* {@return a {@code PermittedSubclasses} attribute}
*
* @param permittedSubclasses the permitted subclasses or subinterfaces
* @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive
* @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive,
* or if the number of permitted subclasses or subinterfaces exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static PermittedSubclassesAttribute ofSymbols(List<ClassDesc> permittedSubclasses) {
return of(Util.entryList(permittedSubclasses));
@ -105,7 +111,9 @@ public sealed interface PermittedSubclassesAttribute
* {@return a {@code PermittedSubclasses} attribute}
*
* @param permittedSubclasses the permitted subclasses or subinterfaces
* @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive
* @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive,
* or if the number of permitted subclasses or subinterfaces exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static PermittedSubclassesAttribute ofSymbols(ClassDesc... permittedSubclasses) {
// List version does defensive copy

View File

@ -68,6 +68,8 @@ public sealed interface RecordAttribute extends Attribute<RecordAttribute>, Clas
* {@return a {@code Record} attribute}
*
* @param components the record components
* @throws IllegalArgumentException if the number of record components
* exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static RecordAttribute of(List<RecordComponentInfo> components) {
return new UnboundAttribute.UnboundRecordAttribute(components);
@ -77,6 +79,8 @@ public sealed interface RecordAttribute extends Attribute<RecordAttribute>, Clas
* {@return a {@code Record} attribute}
*
* @param components the record components
* @throws IllegalArgumentException if the number of record components
* exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
static RecordAttribute of(RecordComponentInfo... components) {
return of(List.of(components));

View File

@ -90,6 +90,8 @@ public sealed interface RecordComponentInfo
* @param name the component name
* @param descriptor the component field descriptor string
* @param attributes the component attributes
* @throws IllegalArgumentException if the number of attributes exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RecordComponentInfo of(Utf8Entry name,
Utf8Entry descriptor,
@ -103,6 +105,8 @@ public sealed interface RecordComponentInfo
* @param name the component name
* @param descriptor the component field descriptor sting
* @param attributes the component attributes
* @throws IllegalArgumentException if the number of attributes exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RecordComponentInfo of(Utf8Entry name,
Utf8Entry descriptor,
@ -116,6 +120,8 @@ public sealed interface RecordComponentInfo
* @param name the component name
* @param descriptor the component symbolic field descriptor
* @param attributes the component attributes
* @throws IllegalArgumentException if the number of attributes exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RecordComponentInfo of(String name,
ClassDesc descriptor,
@ -131,6 +137,8 @@ public sealed interface RecordComponentInfo
* @param name the component name
* @param descriptor the component symbolic field descriptor
* @param attributes the component attributes
* @throws IllegalArgumentException if the number of attributes exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RecordComponentInfo of(String name,
ClassDesc descriptor,

View File

@ -73,6 +73,8 @@ public sealed interface RuntimeInvisibleAnnotationsAttribute
* {@return a {@code RuntimeInvisibleAnnotations} attribute}
*
* @param annotations the annotations
* @throws IllegalArgumentException if the number of annotations exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static RuntimeInvisibleAnnotationsAttribute of(List<Annotation> annotations) {
return new UnboundAttribute.UnboundRuntimeInvisibleAnnotationsAttribute(annotations);
@ -82,6 +84,8 @@ public sealed interface RuntimeInvisibleAnnotationsAttribute
* {@return a {@code RuntimeInvisibleAnnotations} attribute}
*
* @param annotations the annotations
* @throws IllegalArgumentException if the number of annotations exceeds
* the limit of {@link java.lang.classfile##u2 u2}
*/
static RuntimeInvisibleAnnotationsAttribute of(Annotation... annotations) {
return of(List.of(annotations));

View File

@ -86,6 +86,10 @@ public sealed interface RuntimeInvisibleParameterAnnotationsAttribute
* some synthetic or implicit parameters.
*
* @param parameterAnnotations a list of run-time invisible annotations for each parameter
* @throws IllegalArgumentException if the number of parameters exceeds the
* limit of {@link java.lang.classfile##u1 u1}, or the number of
* annotations on any parameter exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static RuntimeInvisibleParameterAnnotationsAttribute of(List<List<Annotation>> parameterAnnotations) {
return new UnboundAttribute.UnboundRuntimeInvisibleParameterAnnotationsAttribute(parameterAnnotations);

View File

@ -79,6 +79,8 @@ public sealed interface RuntimeInvisibleTypeAnnotationsAttribute
* {@return a {@code RuntimeInvisibleTypeAnnotations} attribute}
*
* @param annotations the annotations
* @throws IllegalArgumentException if the number of annotations exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RuntimeInvisibleTypeAnnotationsAttribute of(List<TypeAnnotation> annotations) {
return new UnboundAttribute.UnboundRuntimeInvisibleTypeAnnotationsAttribute(annotations);
@ -88,6 +90,8 @@ public sealed interface RuntimeInvisibleTypeAnnotationsAttribute
* {@return a {@code RuntimeInvisibleTypeAnnotations} attribute}
*
* @param annotations the annotations
* @throws IllegalArgumentException if the number of annotations exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RuntimeInvisibleTypeAnnotationsAttribute of(TypeAnnotation... annotations) {
return of(List.of(annotations));

View File

@ -72,6 +72,8 @@ public sealed interface RuntimeVisibleAnnotationsAttribute
/**
* {@return a {@code RuntimeVisibleAnnotations} attribute}
* @param annotations the annotations
* @throws IllegalArgumentException if the number of annotations exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RuntimeVisibleAnnotationsAttribute of(List<Annotation> annotations) {
return new UnboundAttribute.UnboundRuntimeVisibleAnnotationsAttribute(annotations);
@ -80,6 +82,8 @@ public sealed interface RuntimeVisibleAnnotationsAttribute
/**
* {@return a {@code RuntimeVisibleAnnotations} attribute}
* @param annotations the annotations
* @throws IllegalArgumentException if the number of annotations exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RuntimeVisibleAnnotationsAttribute of(Annotation... annotations) {
return of(List.of(annotations));

View File

@ -88,6 +88,10 @@ public sealed interface RuntimeVisibleParameterAnnotationsAttribute
* some synthetic or implicit parameters.
*
* @param parameterAnnotations a list of run-time visible annotations for each parameter
* @throws IllegalArgumentException if the number of parameters exceeds the
* limit of {@link java.lang.classfile##u1 u1}, or the number of
* annotations on any parameter exceeds the limit of {@link
* java.lang.classfile##u2 u2}
*/
static RuntimeVisibleParameterAnnotationsAttribute of(List<List<Annotation>> parameterAnnotations) {
return new UnboundAttribute.UnboundRuntimeVisibleParameterAnnotationsAttribute(parameterAnnotations);

View File

@ -79,6 +79,8 @@ public sealed interface RuntimeVisibleTypeAnnotationsAttribute
* {@return a {@code RuntimeVisibleTypeAnnotations} attribute}
*
* @param annotations the annotations
* @throws IllegalArgumentException if the number of annotations exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RuntimeVisibleTypeAnnotationsAttribute of(List<TypeAnnotation> annotations) {
return new UnboundAttribute.UnboundRuntimeVisibleTypeAnnotationsAttribute(annotations);
@ -88,6 +90,8 @@ public sealed interface RuntimeVisibleTypeAnnotationsAttribute
* {@return a {@code RuntimeVisibleTypeAnnotations} attribute}
*
* @param annotations the annotations
* @throws IllegalArgumentException if the number of annotations exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
static RuntimeVisibleTypeAnnotationsAttribute of(TypeAnnotation... annotations) {
return of(List.of(annotations));

View File

@ -83,6 +83,8 @@ public sealed interface StackMapFrameInfo
* @param target the location of the frame
* @param locals the complete list of frame locals
* @param stack the complete frame stack
* @throws IllegalArgumentException if the number of types in {@code locals}
* or {@code stack} exceeds the limit of {@link java.lang.classfile##u2 u2}
*/
public static StackMapFrameInfo of(Label target,
List<VerificationTypeInfo> locals,

View File

@ -75,6 +75,8 @@ public sealed interface StackMapTableAttribute
* {@return a stack map table attribute}
*
* @param entries the stack map frames
* @throws IllegalArgumentException if the number of frames exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
public static StackMapTableAttribute of(List<StackMapFrameInfo> entries) {
return new UnboundAttribute.UnboundStackMapTableAttribute(entries);

View File

@ -571,6 +571,8 @@ public sealed interface ConstantPoolBuilder
*
* @param methodReference the bootstrap method
* @param arguments the arguments
* @throws IllegalArgumentException if the number of arguments exceeds the
* limit of {@link java.lang.classfile##u2 u2}
*/
default BootstrapMethodEntry bsmEntry(DirectMethodHandleDesc methodReference,
List<ConstantDesc> arguments) {
@ -586,6 +588,8 @@ public sealed interface ConstantPoolBuilder
*
* @param methodReference the {@code MethodHandleEntry}
* @param arguments the list of {@code LoadableConstantEntry}
* @throws IllegalArgumentException if the number of arguments exceeds the
* limit of {@link java.lang.classfile##u2 u2}
* @see BootstrapMethodEntry#bootstrapMethod()
* BootstrapMethodEntry::bootstrapMethod
* @see BootstrapMethodEntry#arguments() BootstrapMethodEntry::arguments

View File

@ -54,7 +54,8 @@ import jdk.internal.classfile.impl.AbstractPoolEntry;
* Unlike most constant pool entries, a UTF-8 entry is of flexible length: it is
* represented as an array structure, with an {@code u2} for the data length in
* bytes, followed by that number of bytes of Modified UTF-8 data. It can
* represent at most 65535 bytes of data due to the physical restrictions.
* represent at most 65535 bytes of data due to the physical restrictions of
* {@link java.lang.classfile##u2 u2}.
*
* @jvms 4.4.7 The {@code CONSTANT_Utf8_info} Structure
* @see DataInput##modified-utf-8 Modified UTF-8

View File

@ -255,7 +255,7 @@
* or method of any Class-File API class or interface will cause a {@link
* NullPointerException} to be thrown. Additionally,
* invoking a method with an array or collection containing a {@code null} element
* will cause a {@code NullPointerException}, unless otherwise specified. </p>
* will cause a {@code NullPointerException}, unless otherwise specified.
*
* <h3>Symbolic information</h3>
* To describe symbolic information for classes and types, the API uses the

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, 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
@ -40,7 +40,7 @@ public record AnnotationImpl(Utf8Entry className, List<AnnotationElement> elemen
implements Annotation {
public AnnotationImpl {
requireNonNull(className);
elements = List.copyOf(elements);
elements = Util.sanitizeU2List(elements);
}
@Override
@ -189,7 +189,7 @@ public record AnnotationImpl(Utf8Entry className, List<AnnotationElement> elemen
public record OfArrayImpl(List<AnnotationValue> values)
implements AnnotationValue.OfArray {
public OfArrayImpl {
values = List.copyOf(values);
values = Util.sanitizeU2List(values);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, 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
@ -66,6 +66,7 @@ public class AttributeHolder {
public void writeTo(BufWriterImpl buf) {
int attributesCount = this.attributesCount;
Util.checkU2(attributesCount, "attributes count");
buf.writeU2(attributesCount);
for (int i = 0; i < attributesCount; i++) {
Util.writeAttribute(buf, attributes[i]);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, 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
@ -41,13 +41,13 @@ public final class BootstrapMethodEntryImpl implements BootstrapMethodEntry {
private final List<LoadableConstantEntry> arguments;
BootstrapMethodEntryImpl(ConstantPool constantPool, int bsmIndex, int hash,
MethodHandleEntryImpl handle,
List<LoadableConstantEntry> arguments) {
MethodHandleEntryImpl handle,
List<LoadableConstantEntry> arguments) {
this.index = bsmIndex;
this.hash = hash;
this.constantPool = constantPool;
this.handle = handle;
this.arguments = List.copyOf(arguments);
this.arguments = Util.sanitizeU2List(arguments);
}
@Override

View File

@ -276,9 +276,7 @@ public final class BufWriterImpl implements BufWriter {
int strlen = str.length();
int countNonZeroAscii = JLA.countNonZeroAscii(str);
int utflen = utfLen(str, countNonZeroAscii);
if (utflen > 65535) {
throw new IllegalArgumentException("string too long");
}
Util.checkU2(utflen, "utf8 length");
reserveSpace(utflen + 3);
int offset = this.offset;

View File

@ -185,14 +185,14 @@ public final class DirectCodeBuilder
private void writeExceptionHandlers(BufWriterImpl buf) {
int pos = buf.size();
int handlersSize = handlers.size();
Util.checkU2(handlersSize, "exception handlers");
buf.writeU2(handlersSize);
if (handlersSize > 0) {
writeExceptionHandlers(buf, pos);
writeExceptionHandlers(buf, pos, handlersSize);
}
}
private void writeExceptionHandlers(BufWriterImpl buf, int pos) {
int handlersSize = handlers.size();
private void writeExceptionHandlers(BufWriterImpl buf, int pos, int handlersSize) {
for (AbstractPseudoInstruction.ExceptionCatchImpl h : handlers) {
int startPc = labelToBci(h.tryStart());
int endPc = labelToBci(h.tryEnd());
@ -227,6 +227,7 @@ public final class DirectCodeBuilder
public void writeBody(BufWriterImpl b) {
int pos = b.size();
int crSize = characterRangesCount;
Util.checkU2(crSize, "character range count");
b.writeU2(crSize);
for (int i = 0; i < characterRangesCount; i++) {
CharacterRange cr = characterRanges[i];
@ -262,6 +263,7 @@ public final class DirectCodeBuilder
public void writeBody(BufWriterImpl b) {
int pos = b.size();
int lvSize = localVariablesCount;
Util.checkU2(lvSize, "local variable count");
b.writeU2(lvSize);
for (int i = 0; i < localVariablesCount; i++) {
LocalVariable l = localVariables[i];
@ -291,6 +293,7 @@ public final class DirectCodeBuilder
public void writeBody(BufWriterImpl b) {
int pos = b.size();
int lvtSize = localVariableTypesCount;
Util.checkU2(lvtSize, "local variable type count");
b.writeU2(lvtSize);
for (int i = 0; i < localVariableTypesCount; i++) {
LocalVariableType l = localVariableTypes[i];
@ -441,7 +444,7 @@ public final class DirectCodeBuilder
b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE));
push();
b.writeInt(buf.size() + 2);
b.writeU2(buf.size() / 4);
b.writeU2(Util.checkU2(buf.size() / 4, "line number count"));
b.writeBytes(buf);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, 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
@ -35,7 +35,7 @@ public final class InterfacesImpl
private final List<ClassEntry> interfaces;
public InterfacesImpl(List<ClassEntry> interfaces) {
this.interfaces = List.copyOf(interfaces);
this.interfaces = Util.sanitizeU2List(interfaces);
}
@Override

View File

@ -129,6 +129,7 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
if (bsmSize == 0)
return false;
int pos = buf.size();
Util.checkU2(bsmSize, "num bootstrap methods");
if (parent != null && parentBsmSize != 0) {
parent.writeBootstrapMethods(buf);
for (int i = parentBsmSize; i < bsmSize; i++)
@ -160,15 +161,14 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
void writeTo(BufWriterImpl buf) {
int writeFrom = 1;
if (size() >= 65536) {
throw new IllegalArgumentException(String.format("Constant pool is too large %d", size()));
}
buf.writeU2(size());
int mySize = size();
Util.checkU2(mySize, "constant pool count");
buf.writeU2(mySize);
if (parent != null && buf.constantPool().canWriteDirect(this)) {
parent.writeConstantPoolEntries(buf);
writeFrom = parent.size();
}
for (int i = writeFrom; i < size(); ) {
for (int i = writeFrom; i < mySize; ) {
var info = (AbstractPoolEntry) entryByIndex(i);
info.writeTo(buf);
i += info.width();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, 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
@ -303,8 +303,8 @@ public class StackMapDecoder {
implements StackMapFrameInfo {
public StackMapFrameImpl {
requireNonNull(target);
locals = List.copyOf(locals);
stack = List.copyOf(stack);
locals = Util.sanitizeU2List(locals);
stack = Util.sanitizeU2List(stack);
}
}
}

View File

@ -108,7 +108,7 @@ public final class TargetInfoImpl {
public LocalVarTargetImpl(TargetType targetType, List<LocalVarTargetInfo> table) {
this.targetType = checkValid(targetType, TARGET_LOCAL_VARIABLE, TARGET_RESOURCE_VARIABLE);
this.table = List.copyOf(table);
this.table = Util.sanitizeU2List(table);
}
@Override
public int size() {

View File

@ -174,7 +174,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundExceptionsAttribute(List<ClassEntry> exceptions) {
super(Attributes.exceptions());
this.exceptions = List.copyOf(exceptions);
this.exceptions = Util.sanitizeU2List(exceptions);
}
@Override
@ -244,7 +244,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundStackMapTableAttribute(List<StackMapFrameInfo> entries) {
super(Attributes.stackMapTable());
this.entries = List.copyOf(entries);
this.entries = Util.sanitizeU2List(entries);
}
@Override
@ -268,7 +268,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundInnerClassesAttribute(List<InnerClassInfo> innerClasses) {
super(Attributes.innerClasses());
this.innerClasses = List.copyOf(innerClasses);
this.innerClasses = Util.sanitizeU2List(innerClasses);
}
@Override
@ -292,7 +292,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundRecordAttribute(List<RecordComponentInfo> components) {
super(Attributes.record());
this.components = List.copyOf(components);
this.components = Util.sanitizeU2List(components);
}
@Override
@ -347,7 +347,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundMethodParametersAttribute(List<MethodParameterInfo> parameters) {
super(Attributes.methodParameters());
this.parameters = List.copyOf(parameters);
this.parameters = Util.sanitizeU1List(parameters);
}
@Override
@ -421,7 +421,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundModuleHashesAttribute(Utf8Entry algorithm, List<ModuleHashInfo> hashes) {
super(Attributes.moduleHashes());
this.algorithm = requireNonNull(algorithm);
this.hashes = List.copyOf(hashes);
this.hashes = Util.sanitizeU2List(hashes);
}
@Override
@ -446,16 +446,16 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE_PACKAGES);
private final Collection<PackageEntry> packages;
private final List<PackageEntry> packages;
public UnboundModulePackagesAttribute(Collection<PackageEntry> packages) {
super(Attributes.modulePackages());
this.packages = List.copyOf(packages);
this.packages = Util.sanitizeU2List(packages);
}
@Override
public List<PackageEntry> packages() {
return List.copyOf(packages);
return packages;
}
@Override
@ -498,7 +498,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundPermittedSubclassesAttribute(List<ClassEntry> permittedSubclasses) {
super(Attributes.permittedSubclasses());
this.permittedSubclasses = List.copyOf(permittedSubclasses);
this.permittedSubclasses = Util.sanitizeU2List(permittedSubclasses);
}
@Override
@ -522,7 +522,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundNestMembersAttribute(List<ClassEntry> memberEntries) {
super(Attributes.nestMembers());
this.memberEntries = List.copyOf(memberEntries);
this.memberEntries = Util.sanitizeU2List(memberEntries);
}
@Override
@ -642,7 +642,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundCharacterRangeTableAttribute(List<CharacterRangeInfo> ranges) {
super(Attributes.characterRangeTable());
this.ranges = List.copyOf(ranges);
this.ranges = Util.sanitizeU2List(ranges);
}
@Override
@ -666,7 +666,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundLineNumberTableAttribute(List<LineNumberInfo> lines) {
super(Attributes.lineNumberTable());
this.lines = List.copyOf(lines);
this.lines = Util.sanitizeU2List(lines);
}
@Override
@ -690,7 +690,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundLocalVariableTableAttribute(List<LocalVariableInfo> locals) {
super(Attributes.localVariableTable());
this.locals = List.copyOf(locals);
this.locals = Util.sanitizeU2List(locals);
}
@Override
@ -714,7 +714,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundLocalVariableTypeTableAttribute(List<LocalVariableTypeInfo> locals) {
super(Attributes.localVariableTypeTable());
this.locals = List.copyOf(locals);
this.locals = Util.sanitizeU2List(locals);
}
@Override
@ -738,7 +738,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundRuntimeVisibleAnnotationsAttribute(List<Annotation> elements) {
super(Attributes.runtimeVisibleAnnotations());
this.elements = List.copyOf(elements);
this.elements = Util.sanitizeU2List(elements);
}
@Override
@ -762,7 +762,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundRuntimeInvisibleAnnotationsAttribute(List<Annotation> elements) {
super(Attributes.runtimeInvisibleAnnotations());
this.elements = List.copyOf(elements);
this.elements = Util.sanitizeU2List(elements);
}
@Override
@ -786,13 +786,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundRuntimeVisibleParameterAnnotationsAttribute(List<List<Annotation>> elements) {
super(Attributes.runtimeVisibleParameterAnnotations());
// deep copy
var array = elements.toArray().clone();
for (int i = 0; i < array.length; i++) {
array[i] = List.copyOf((List<?>) array[i]);
}
this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array);
this.elements = Util.sanitizeParameterAnnotations(elements);
}
@Override
@ -816,13 +810,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List<List<Annotation>> elements) {
super(Attributes.runtimeInvisibleParameterAnnotations());
// deep copy
var array = elements.toArray().clone();
for (int i = 0; i < array.length; i++) {
array[i] = List.copyOf((List<?>) array[i]);
}
this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array);
this.elements = Util.sanitizeParameterAnnotations(elements);
}
@Override
@ -846,7 +834,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundRuntimeVisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
super(Attributes.runtimeVisibleTypeAnnotations());
this.elements = List.copyOf(elements);
this.elements = Util.sanitizeU2List(elements);
}
@Override
@ -870,7 +858,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
super(Attributes.runtimeInvisibleTypeAnnotations());
this.elements = List.copyOf(elements);
this.elements = Util.sanitizeU2List(elements);
}
@Override
@ -955,7 +943,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundModuleExportInfo {
requireNonNull(exportedPackage);
Util.checkFlags(exportsFlagsMask);
exportsTo = List.copyOf(exportsTo);
exportsTo = Util.sanitizeU2List(exportsTo);
}
}
@ -973,7 +961,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundModuleOpenInfo {
requireNonNull(openedPackage);
Util.checkFlags(opensFlagsMask);
opensTo = List.copyOf(opensTo);
opensTo = Util.sanitizeU2List(opensTo);
}
}
@ -982,7 +970,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
implements ModuleProvideInfo {
public UnboundModuleProvideInfo {
requireNonNull(provides);
providesWith = List.copyOf(providesWith);
providesWith = Util.sanitizeU2List(providesWith);
}
}
@ -1003,7 +991,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundRecordComponentInfo {
requireNonNull(name);
requireNonNull(descriptor);
attributes = List.copyOf(attributes);
attributes = Util.sanitizeU2List(attributes);
}
}
@ -1013,7 +1001,7 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
public UnboundTypeAnnotation {
requireNonNull(targetInfo);
targetPath = List.copyOf(targetPath);
targetPath = Util.sanitizeU1List(targetPath);
requireNonNull(annotation);
}
}
@ -1047,11 +1035,11 @@ public abstract sealed class UnboundAttribute<T extends Attribute<T>>
this.moduleName = requireNonNull(moduleName);
this.moduleFlags = Util.checkFlags(moduleFlags);
this.moduleVersion = moduleVersion;
this.requires = List.copyOf(requires);
this.exports = List.copyOf(exports);
this.opens = List.copyOf(opens);
this.uses = List.copyOf(uses);
this.provides = List.copyOf(provides);
this.requires = Util.sanitizeU2List(requires);
this.exports = Util.sanitizeU2List(exports);
this.opens = Util.sanitizeU2List(opens);
this.uses = Util.sanitizeU2List(uses);
this.provides = Util.sanitizeU2List(provides);
}
@Override

View File

@ -146,6 +146,33 @@ public final class Util {
: ClassDesc.ofInternalName(classInternalNameOrArrayDesc);
}
/// Sanitizes an input list to make it immutable, and verify its size can
/// be represented with U1, throwing IAE otherwise.
public static <T> List<T> sanitizeU1List(List<T> input) {
var copy = List.copyOf(input);
checkU1(copy.size(), "list size");
return copy;
}
/// Sanitizes an input list to make it immutable, and verify its size can
/// be represented with U2, throwing IAE otherwise.
public static <T> List<T> sanitizeU2List(Collection<T> input) {
var copy = List.copyOf(input);
checkU2(copy.size(), "list size");
return copy;
}
/// Sanitizes an input nested list of parameter annotations.
public static List<List<Annotation>> sanitizeParameterAnnotations(List<List<Annotation>> input) {
var array = input.toArray().clone();
checkU1(array.length, "parameter count");
for (int i = 0; i < array.length; i++) {
array[i] = sanitizeU2List((List<?>) array[i]);
}
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array);
}
public static<T, U> List<U> mappedList(List<? extends T> list, Function<T, U> mapper) {
return new AbstractList<>() {
@Override
@ -259,6 +286,7 @@ public final class Util {
@ForceInline
public static void writeAttributes(BufWriterImpl buf, List<? extends Attribute<?>> list) {
int size = list.size();
Util.checkU2(size, "attributes count");
buf.writeU2(size);
for (int i = 0; i < size; i++) {
writeAttribute(buf, list.get(i));
@ -267,6 +295,7 @@ public final class Util {
@ForceInline
static void writeList(BufWriterImpl buf, Writable[] array, int size) {
Util.checkU2(size, "member count");
buf.writeU2(size);
for (int i = 0; i < size; i++) {
array[i].writeTo(buf);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, 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
@ -23,17 +23,22 @@
/*
* @test
* @bug 8320360 8330684 8331320 8331655 8331940 8332486 8335820 8336833
* @bug 8320360 8330684 8331320 8331655 8331940 8332486 8335820 8336833 8361635
* @summary Testing ClassFile limits.
* @run junit LimitsTest
*/
import java.lang.classfile.AttributeMapper;
import java.lang.classfile.AttributedElement;
import java.lang.classfile.Attributes;
import java.lang.classfile.constantpool.PoolEntry;
import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.MethodTypeDesc;
import java.lang.classfile.BufWriter;
import java.lang.classfile.ClassFile;
import java.lang.classfile.ClassReader;
import java.lang.classfile.CodeBuilder;
import java.lang.classfile.CustomAttribute;
import java.lang.classfile.Label;
import java.lang.classfile.Opcode;
import java.lang.classfile.Signature;
import java.lang.classfile.attribute.CodeAttribute;
import java.lang.classfile.attribute.LineNumberInfo;
import java.lang.classfile.attribute.LineNumberTableAttribute;
@ -41,8 +46,16 @@ import java.lang.classfile.attribute.LocalVariableTableAttribute;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.ConstantPoolException;
import java.lang.classfile.constantpool.IntegerEntry;
import java.lang.classfile.constantpool.PoolEntry;
import java.lang.classfile.constantpool.Utf8Entry;
import java.lang.classfile.instruction.SwitchCase;
import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.MethodTypeDesc;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import jdk.internal.classfile.impl.BufWriterImpl;
import jdk.internal.classfile.impl.DirectCodeBuilder;
@ -51,6 +64,8 @@ import jdk.internal.classfile.impl.LabelContext;
import jdk.internal.classfile.impl.UnboundAttribute;
import org.junit.jupiter.api.Test;
import static java.lang.classfile.ClassFile.ACC_STATIC;
import static java.lang.constant.ConstantDescs.*;
import static org.junit.jupiter.api.Assertions.*;
class LimitsTest {
@ -73,6 +88,114 @@ class LimitsTest {
}));
}
@Test
void testBsmOverLimit() {
AtomicBoolean reached = new AtomicBoolean();
assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> {
var cp = clb.constantPool();
var mhe = cp.methodHandleEntry(BSM_GET_STATIC_FINAL);
var digits = new IntegerEntry[10];
for (int i = 0; i < 10; i++) {
digits[i] = cp.intEntry(i);
}
int lastIndex = -1;
for (int i = 0; i < 66000; i++) {
lastIndex = cp.bsmEntry(mhe, List.of(
digits[i / 10000 % 10],
digits[i / 1000 % 10],
digits[i / 100 % 10],
digits[i / 10 % 10],
digits[i / 1 % 10])).bsmIndex();
}
assertEquals(65999, lastIndex);
reached.set(true);
}));
assertTrue(reached.get());
}
@Test
void testTooManyFields() {
AtomicBoolean reached = new AtomicBoolean();
assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> {
for (int i = 1; i < 66000; i++) {
clb.withField("f", CD_int, 0);
}
reached.set(true);
}));
assertTrue(reached.get());
}
@Test
void testTooManyMethods() {
AtomicBoolean reached = new AtomicBoolean();
assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> {
for (int i = 1; i < 66000; i++) {
clb.withMethodBody("m", MTD_void, 0, CodeBuilder::return_);
}
reached.set(true);
}));
assertTrue(reached.get());
}
static final class MyAttribute extends CustomAttribute<MyAttribute> {
static final MyAttribute INSTANCE = new MyAttribute();
private enum Mapper implements AttributeMapper<MyAttribute> {
INSTANCE;
@Override
public MyAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) {
throw new UnsupportedOperationException();
}
@Override
public void writeAttribute(BufWriter buf, MyAttribute attr) {
buf.writeIndex(buf.constantPool().utf8Entry("MyAttribute"));
buf.writeInt(0);
}
@Override
public boolean allowMultiple() {
return true;
}
@Override
public AttributeStability stability() {
return AttributeStability.STATELESS;
}
}
private MyAttribute() {
super(Mapper.INSTANCE);
}
}
@Test
void testTooManyClassAttributes() {
AtomicBoolean reached = new AtomicBoolean();
assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> {
for (int i = 1; i < 66000; i++) {
clb.with(MyAttribute.INSTANCE);
}
reached.set(true);
}));
assertTrue(reached.get());
}
@Test
void testTooManyFieldAttributes() {
AtomicBoolean reached = new AtomicBoolean();
assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> clb.withField("f", CD_int, fb -> {
for (int i = 1; i < 66000; i++) {
fb.with(MyAttribute.INSTANCE);
}
reached.set(true);
})));
assertTrue(reached.get());
}
@Test
void testCodeOverLimit() {
assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(ClassDesc.of("BigClass"), cb -> cb.withMethodBody(
@ -99,6 +222,91 @@ class LimitsTest {
assertThrows(IllegalArgumentException.class, () -> lc.getLabel(10));
}
private static void testPseudoOverflow(BiConsumer<CodeBuilder, Label> handler) {
ClassFile cf = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS);
AtomicBoolean reached = new AtomicBoolean(false);
assertDoesNotThrow(() -> cf.build(CD_Void, cb -> cb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> {
cob.nop();
var label = cob.newLabel();
for (int i = 0; i < 65535; i++) {
handler.accept(cob, label);
}
cob.labelBinding(label);
cob.return_();
reached.set(true);
})));
assertTrue(reached.get());
reached.set(false);
assertThrows(IllegalArgumentException.class, () -> cf.build(CD_Void, cb -> cb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> {
cob.nop();
var label = cob.newLabel();
for (int i = 0; i < 65536; i++) {
handler.accept(cob, label);
}
cob.labelBinding(label);
cob.return_();
reached.set(true);
})));
assertTrue(reached.get());
}
@Test
void testExceptionCatchOverflow() {
testPseudoOverflow((cob, label) -> cob.exceptionCatch(cob.startLabel(), label, label, CD_Throwable));
}
@Test
void testLocalVariableOverflow() {
testPseudoOverflow((cob, label) -> cob.localVariable(0, "fake", CD_int, cob.startLabel(), label));
}
@Test
void testLocalVariableTypeOverflow() {
testPseudoOverflow((cob, label) -> cob.localVariableType(0, "fake", Signature.of(CD_int), cob.startLabel(), label));
}
@Test
void testCharacterRangeOverflow() {
testPseudoOverflow((cob, label) -> cob.characterRange(cob.startLabel(), label, 0, 0, 0));
}
// LineNumber deduplicates so cannot really overflow
@Test
void testHugeLookupswitch() {
assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> clb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> {
var l = cob.newLabel();
// 10000 * 8 > 65535
var cases = new ArrayList<SwitchCase>(10000);
for (int i = 0; i < 10000; i++) {
cases.add(SwitchCase.of(i, l));
}
cob.lookupswitch(l, cases);
cob.labelBinding(l);
cob.return_();
})));
}
@Test
void testHugeTableswitch() {
assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> clb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> {
var l = cob.newLabel();
// 20000 * 4 > 65535
cob.tableswitch(-10000, 10000, l, List.of());
cob.labelBinding(l);
cob.return_();
})));
}
@Test
void testHugeUtf8Entry() {
var longString = String.valueOf((char) 0x800).repeat(22000);
assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> {
clb.constantPool().utf8Entry(longString);
}));
}
@Test
void testSupportedClassVersion() {
var cf = ClassFile.of();

View File

@ -0,0 +1,348 @@
/*
* Copyright (c) 2025, 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.
*
* 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
* @bug 8361635
* @summary Testing list size validation in class file format.
* @run junit ListValidationTest
*/
import java.lang.classfile.Annotation;
import java.lang.classfile.AnnotationElement;
import java.lang.classfile.AnnotationValue;
import java.lang.classfile.ClassFile;
import java.lang.classfile.Interfaces;
import java.lang.classfile.Label;
import java.lang.classfile.TypeAnnotation;
import java.lang.classfile.attribute.*;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.constant.ModuleDesc;
import java.lang.constant.PackageDesc;
import java.util.List;
import java.util.Optional;
import jdk.internal.classfile.impl.TemporaryConstantPool;
import jdk.internal.classfile.impl.UnboundAttribute;
import org.junit.jupiter.api.Test;
import static java.lang.constant.ConstantDescs.*;
import static java.util.Collections.nCopies;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
class ListValidationTest {
@Test
void testAnnotationElements() {
var e = AnnotationElement.ofInt("dummy", 0);
assertDoesNotThrow(() -> Annotation.of(CD_String, nCopies(65535, e)));
assertThrows(IllegalArgumentException.class, () -> Annotation.of(CD_String, nCopies(66000, e)));
}
@Test
void testAnnotationArrayValue() {
var v = AnnotationValue.ofInt(0);
assertDoesNotThrow(() -> AnnotationValue.ofArray(nCopies(65535, v)));
assertThrows(IllegalArgumentException.class, () -> AnnotationValue.ofArray(nCopies(66000, v)));
}
@Test
void testTypeAnnotationPath() {
var anno = Annotation.of(CD_String);
assertDoesNotThrow(() -> TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), nCopies(255, TypeAnnotation.TypePathComponent.INNER_TYPE), anno));
assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), nCopies(256, TypeAnnotation.TypePathComponent.INNER_TYPE), anno));
}
@Test
void testBsmArgs() {
var cpb = ConstantPoolBuilder.of();
assertDoesNotThrow(() -> cpb.bsmEntry(BSM_INVOKE, nCopies(65535, 0)));
assertThrows(IllegalArgumentException.class, () -> cpb.bsmEntry(BSM_INVOKE, nCopies(66000, 0)));
}
@Test
void testInterfaces() {
var cpb = ConstantPoolBuilder.of();
assertDoesNotThrow(() -> Interfaces.ofSymbols(nCopies(65535, CD_Number)));
assertThrows(IllegalArgumentException.class, () -> cpb.bsmEntry(BSM_INVOKE, nCopies(66000, 0)));
}
@Test
void testStackMapFrame() {
Label label = dummyLabel();
assertDoesNotThrow(() -> StackMapFrameInfo.of(label,
nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER),
nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE)));
assertThrows(IllegalArgumentException.class, () -> StackMapFrameInfo.of(label,
nCopies(66000, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER),
nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE)));
assertThrows(IllegalArgumentException.class, () -> StackMapFrameInfo.of(label,
nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER),
nCopies(66000, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE)));
}
@Test
void testTypeAnnotationLocalVarTarget() {
Label label = dummyLabel();
assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofLocalVariable(nCopies(65535, TypeAnnotation.LocalVarTargetInfo.of(label, label, 0))));
assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofLocalVariable(nCopies(66000, TypeAnnotation.LocalVarTargetInfo.of(label, label, 0))));
}
@Test
void testExceptionsAttribute() {
assertDoesNotThrow(() -> ExceptionsAttribute.ofSymbols(nCopies(65535, CD_Throwable)));
assertThrows(IllegalArgumentException.class, () -> ExceptionsAttribute.ofSymbols(nCopies(66000, CD_Throwable)));
}
@Test
void testStackMapTableAttribute() {
var frame = StackMapFrameInfo.of(dummyLabel(),
nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER),
nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE));
assertDoesNotThrow(() -> StackMapTableAttribute.of(nCopies(65535, frame)));
assertThrows(IllegalArgumentException.class, () -> StackMapTableAttribute.of(nCopies(66000, frame)));
}
@Test
void testInnerClassesAttribute() {
var entry = InnerClassInfo.of(CD_Void, Optional.empty(), Optional.empty(), 0);
assertDoesNotThrow(() -> InnerClassesAttribute.of(nCopies(65535, entry)));
assertThrows(IllegalArgumentException.class, () -> InnerClassesAttribute.of(nCopies(66000, entry)));
}
@Test
void testRecordAttribute() {
var component = RecordComponentInfo.of("hello", CD_int, List.of());
assertDoesNotThrow(() -> RecordAttribute.of(nCopies(65535, component)));
assertThrows(IllegalArgumentException.class, () -> RecordAttribute.of(nCopies(66000, component)));
}
@Test
void testMethodParametersAttribute() {
var component = MethodParameterInfo.of(Optional.empty(), 0);
assertDoesNotThrow(() -> MethodParametersAttribute.of(nCopies(255, component)));
assertThrows(IllegalArgumentException.class, () -> MethodParametersAttribute.of(nCopies(300, component)));
}
@Test
void testModuleHashesAttribute() {
var hash = ModuleHashInfo.of(ModuleDesc.of("java.base"), new byte[0]);
assertDoesNotThrow(() -> ModuleHashesAttribute.of("dummy", nCopies(65535, hash)));
assertThrows(IllegalArgumentException.class, () -> ModuleHashesAttribute.of("dummy", nCopies(66000, hash)));
}
@Test
void testModulePackagesAttribute() {
var pkgDesc = PackageDesc.of("java.io");
assertDoesNotThrow(() -> ModulePackagesAttribute.ofNames(nCopies(65535, pkgDesc)));
assertThrows(IllegalArgumentException.class, () -> ModulePackagesAttribute.ofNames(nCopies(66000, pkgDesc)));
}
@Test
void testPermittedSubclassesAttribute() {
assertDoesNotThrow(() -> PermittedSubclassesAttribute.ofSymbols(nCopies(65535, CD_Collection)));
assertThrows(IllegalArgumentException.class, () -> PermittedSubclassesAttribute.ofSymbols(nCopies(66000, CD_Collection)));
}
@Test
void testNestMembersAttribute() {
assertDoesNotThrow(() -> NestMembersAttribute.ofSymbols(nCopies(65535, CD_Collection)));
assertThrows(IllegalArgumentException.class, () -> NestMembersAttribute.ofSymbols(nCopies(66000, CD_Collection)));
}
@Test
void testCharacterRangeTableAttribute() {
var range = CharacterRangeInfo.of(0, 0, 0, 0, 0);
assertDoesNotThrow(() -> CharacterRangeTableAttribute.of(nCopies(65535, range)));
assertThrows(IllegalArgumentException.class, () -> CharacterRangeTableAttribute.of(nCopies(66000, range)));
}
@Test
void testLineNumberTableAttribute() {
var lineNumber = LineNumberInfo.of(0, 0);
assertDoesNotThrow(() -> LineNumberTableAttribute.of(nCopies(65535, lineNumber)));
assertThrows(IllegalArgumentException.class, () -> LineNumberTableAttribute.of(nCopies(66000, lineNumber)));
}
@Test
void testLocalVariableTableAttribute() {
var utf8 = TemporaryConstantPool.INSTANCE.utf8Entry("dummy");
var localVariable = new UnboundAttribute.UnboundLocalVariableInfo(0, 0, utf8, utf8, 0);
assertDoesNotThrow(() -> LocalVariableTableAttribute.of(nCopies(65535, localVariable)));
assertThrows(IllegalArgumentException.class, () -> LocalVariableTableAttribute.of(nCopies(66000, localVariable)));
}
@Test
void testLocalVariableTypeTableAttribute() {
var utf8 = TemporaryConstantPool.INSTANCE.utf8Entry("dummy");
var localVariableType = new UnboundAttribute.UnboundLocalVariableTypeInfo(0, 0, utf8, utf8, 0);
assertDoesNotThrow(() -> LocalVariableTypeTableAttribute.of(nCopies(65535, localVariableType)));
assertThrows(IllegalArgumentException.class, () -> LocalVariableTypeTableAttribute.of(nCopies(66000, localVariableType)));
}
@Test
void testRuntimeVisibleAnnotationsAttribute() {
var anno = Annotation.of(CD_String);
assertDoesNotThrow(() -> RuntimeVisibleAnnotationsAttribute.of(nCopies(65535, anno)));
assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleAnnotationsAttribute.of(nCopies(66000, anno)));
}
@Test
void testRuntimeInvisibleAnnotationsAttribute() {
var anno = Annotation.of(CD_String);
assertDoesNotThrow(() -> RuntimeInvisibleAnnotationsAttribute.of(nCopies(65535, anno)));
assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleAnnotationsAttribute.of(nCopies(66000, anno)));
}
@Test
void testRuntimeVisibleParameterAnnotationsAttributeTopLevel() {
assertDoesNotThrow(() -> RuntimeVisibleParameterAnnotationsAttribute.of(nCopies(255, List.of())));
assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleParameterAnnotationsAttribute.of(nCopies(256, List.of())));
}
@Test
void testRuntimeInvisibleParameterAnnotationsAttributeTopLevel() {
assertDoesNotThrow(() -> RuntimeInvisibleParameterAnnotationsAttribute.of(nCopies(255, List.of())));
assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleParameterAnnotationsAttribute.of(nCopies(256, List.of())));
}
@Test
void testRuntimeVisibleParameterAnnotationsAttributeNested() {
var anno = Annotation.of(CD_String);
assertDoesNotThrow(() -> RuntimeVisibleParameterAnnotationsAttribute.of(List.of(nCopies(65535, anno))));
assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleParameterAnnotationsAttribute.of(List.of(nCopies(65536, anno))));
}
@Test
void testRuntimeInvisibleParameterAnnotationsAttributeNested() {
var anno = Annotation.of(CD_String);
assertDoesNotThrow(() -> RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(nCopies(65535, anno))));
assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(nCopies(65536, anno))));
}
@Test
void testRuntimeVisibleTypeAnnotationsAttribute() {
var anno = TypeAnnotation.of(TypeAnnotation.TargetInfo.ofMethodReturn(), List.of(), Annotation.of(CD_String));
assertDoesNotThrow(() -> RuntimeVisibleTypeAnnotationsAttribute.of(nCopies(65535, anno)));
assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleTypeAnnotationsAttribute.of(nCopies(66000, anno)));
}
@Test
void testRuntimeInvisibleTypeAnnotationsAttribute() {
var anno = TypeAnnotation.of(TypeAnnotation.TargetInfo.ofMethodReturn(), List.of(), Annotation.of(CD_String));
assertDoesNotThrow(() -> RuntimeInvisibleTypeAnnotationsAttribute.of(nCopies(65535, anno)));
assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleTypeAnnotationsAttribute.of(nCopies(66000, anno)));
}
@Test
void testModuleExportEntry() {
var pkg = PackageDesc.of("dummy.test");
var mod = ModuleDesc.of("the.other");
assertDoesNotThrow(() -> ModuleExportInfo.of(pkg, 0, nCopies(65535, mod)));
assertThrows(IllegalArgumentException.class, () -> ModuleExportInfo.of(pkg, 0, nCopies(66000, mod)));
}
@Test
void testModuleOpenEntry() {
var pkg = PackageDesc.of("dummy.test");
var mod = ModuleDesc.of("the.other");
assertDoesNotThrow(() -> ModuleOpenInfo.of(pkg, 0, nCopies(65535, mod)));
assertThrows(IllegalArgumentException.class, () -> ModuleOpenInfo.of(pkg, 0, nCopies(66000, mod)));
}
@Test
void testModuleProvideEntry() {
assertDoesNotThrow(() -> ModuleProvideInfo.of(CD_Object, nCopies(65535, CD_String)));
assertThrows(IllegalArgumentException.class, () -> ModuleProvideInfo.of(CD_Object, nCopies(66000, CD_String)));
}
@Test
void testRecordComponentAttributes() {
var attr = SyntheticAttribute.of();
assertDoesNotThrow(() -> RecordComponentInfo.of("dummy", CD_int, nCopies(65535, attr)));
assertThrows(IllegalArgumentException.class, () -> RecordComponentInfo.of("dummy", CD_int, nCopies(66000, attr)));
}
@Test
void testModuleAttribute() {
var md = ModuleDesc.of("java.base");
var pkg = PackageDesc.of("java.lang");
var require = ModuleRequireInfo.of(md, 0, null);
var export = ModuleExportInfo.of(pkg, 0, List.of());
var provide = ModuleProvideInfo.of(CD_Object, List.of());
var open = ModuleOpenInfo.of(pkg, 0, List.of());
var classEntry = TemporaryConstantPool.INSTANCE.classEntry(CD_String);
var moduleEntry = TemporaryConstantPool.INSTANCE.moduleEntry(md);
assertDoesNotThrow(() -> ModuleAttribute.of(moduleEntry, 0, null,
nCopies(65535, require),
nCopies(65535, export),
nCopies(65535, open),
nCopies(65535, classEntry),
nCopies(65535, provide)
));
assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null,
nCopies(66000, require),
nCopies(65535, export),
nCopies(65535, open),
nCopies(65535, classEntry),
nCopies(65535, provide)
));
assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null,
nCopies(65535, require),
nCopies(66000, export),
nCopies(65535, open),
nCopies(65535, classEntry),
nCopies(65535, provide)
));
assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null,
nCopies(65535, require),
nCopies(65535, export),
nCopies(66000, open),
nCopies(65535, classEntry),
nCopies(65535, provide)
));
assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null,
nCopies(65535, require),
nCopies(65535, export),
nCopies(65535, open),
nCopies(66000, classEntry),
nCopies(65535, provide)
));
assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null,
nCopies(65535, require),
nCopies(65535, export),
nCopies(65535, open),
nCopies(65535, classEntry),
nCopies(66000, provide)
));
}
private static Label dummyLabel() {
Label[] capture = new Label[1];
ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> {
capture[0] = cob.startLabel();
cob.return_();
}));
return capture[0];
}
}