-
Bug
-
Resolution: Fixed
-
P4
-
11, 17, 18, 19, 20
-
b24
-
generic
-
generic
-
Verified
A DESCRIPTION OF THE PROBLEM :
When `Class.getEnumConstants()` is called on a bad enum class where `values()` is an instance method, or returns a non‑array, then it throws `NullPointerException` or `ClassCastException` respectively.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached Java and Jasm program. Might need https://github.com/openjdk/asmtools/pull/46 to compile successfully.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program completes successfully.
ACTUAL -
The program throws `java.lang.AssertionError`:
```
Exception in thread "main" java.lang.AssertionError: [java.lang.NullPointerException, java.lang.ClassCastException: class java.lang.Object cannot be cast to class [Ljava.lang.Object; (java.lang.Object and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')]
at Test.main(Test.java:28)
Suppressed: java.lang.NullPointerException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:76)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:52)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at java.base/java.lang.Class.getEnumConstantsShared(Class.java:3894)
at java.base/java.lang.Class.getEnumConstants(Class.java:3869)
at Test.main(Test.java:14)
Suppressed: java.lang.ClassCastException: class java.lang.Object cannot be cast to class [Ljava.lang.Object; (java.lang.Object and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')
at java.base/java.lang.Class.getEnumConstantsShared(Class.java:3894)
at java.base/java.lang.Class.getEnumConstants(Class.java:3869)
at Test.main(Test.java:21)
```
---------- BEGIN SOURCE ----------
/// BEGIN JAVA
import java.util.ArrayList;
import java.util.List;
final class Test {
public static void main(final String... args) throws Throwable {
final List<Throwable> errors = new ArrayList<>();
try {
final Object actual = BadEnum1.class.getEnumConstants();
if (actual != null) throw new AssertionError("Expected BadEnum1.class.getEnumConstants() to return null, got " + actual);
} catch (final Throwable t) {
errors.add(t);
}
try {
final Object actual = BadEnum2.class.getEnumConstants();
if (actual != null) throw new AssertionError("Expected BadEnum2.class.getEnumConstants() to return null, got " + actual);
} catch (final Throwable t) {
errors.add(t);
}
if (!errors.isEmpty()) {
final AssertionError err = new AssertionError(List.copyOf(errors));
errors.forEach(err::addSuppressed);
throw err;
}
}
}
/// END JAVA
/// BEGIN JASM
super final enum class BadEnum1
extends java/lang/Enum
version 52:0
{
Signature "Ljava/lang/Enum<LBadEnum1;>;";
private static final synthetic Field $VALUES:"[LBadEnum1;";
public Method values:"()[LBadEnum1;"
stack 1
{
getstatic Field $VALUES:"[LBadEnum1;";
invokevirtual Method "[LBadEnum1;".clone:"()Ljava/lang/Object;";
checkcast class "[LBadEnum1;";
areturn;
}
public static Method valueOf:"(Ljava/lang/String;)LBadEnum1;"
stack 2
0: #{name mandated}
{
ldc class BadEnum1;
aload_0;
invokestatic Method java/lang/Enum.valueOf:"(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;";
checkcast class BadEnum1;
areturn;
}
private Method "<init>":"(Ljava/lang/String;I)V":"()V"
stack 3
0: #{$enum$name synthetic}
1: #{$enum$ordinal synthetic}
{
aload_0;
aload_1;
iload_2;
invokespecial Method java/lang/Enum."<init>":"(Ljava/lang/String;I)V";
return;
}
private static synthetic Method $values:"()[LBadEnum1;"
stack 1
{
iconst_0;
anewarray class BadEnum1;
areturn;
}
static Method "<clinit>":"()V"
stack 1
{
invokestatic Method $values:"()[LBadEnum1;";
putstatic Field $VALUES:"[LBadEnum1;";
return;
}
}
super final enum class BadEnum2
extends java/lang/Enum
version 52:0
{
Signature "Ljava/lang/Enum<LBadEnum2;>;";
private static final synthetic Field $VALUES:"[LBadEnum2;";
public static Method values:"()Ljava/lang/Object;"
stack 2
{
new class java/lang/Object;
dup;
invokespecial Method java/lang/Object."<init>":"()V";
areturn;
}
public static Method valueOf:"(Ljava/lang/String;)LBadEnum2;"
stack 2
0: #{name mandated}
{
ldc class BadEnum2;
aload_0;
invokestatic Method java/lang/Enum.valueOf:"(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;";
checkcast class BadEnum2;
areturn;
}
private Method "<init>":"(Ljava/lang/String;I)V":"()V"
stack 3
0: #{$enum$name synthetic}
1: #{$enum$ordinal synthetic}
{
aload_0;
aload_1;
iload_2;
invokespecial Method java/lang/Enum."<init>":"(Ljava/lang/String;I)V";
return;
}
private static synthetic Method $values:"()[LBadEnum2;"
stack 1
{
iconst_0;
anewarray class BadEnum2;
areturn;
}
static Method "<clinit>":"()V"
stack 1
{
invokestatic Method $values:"()[LBadEnum2;";
putstatic Field $VALUES:"[LBadEnum2;";
return;
}
}
/// END JASM
---------- END SOURCE ----------
FREQUENCY : always
When `Class.getEnumConstants()` is called on a bad enum class where `values()` is an instance method, or returns a non‑array, then it throws `NullPointerException` or `ClassCastException` respectively.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached Java and Jasm program. Might need https://github.com/openjdk/asmtools/pull/46 to compile successfully.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program completes successfully.
ACTUAL -
The program throws `java.lang.AssertionError`:
```
Exception in thread "main" java.lang.AssertionError: [java.lang.NullPointerException, java.lang.ClassCastException: class java.lang.Object cannot be cast to class [Ljava.lang.Object; (java.lang.Object and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')]
at Test.main(Test.java:28)
Suppressed: java.lang.NullPointerException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:76)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:52)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at java.base/java.lang.Class.getEnumConstantsShared(Class.java:3894)
at java.base/java.lang.Class.getEnumConstants(Class.java:3869)
at Test.main(Test.java:14)
Suppressed: java.lang.ClassCastException: class java.lang.Object cannot be cast to class [Ljava.lang.Object; (java.lang.Object and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')
at java.base/java.lang.Class.getEnumConstantsShared(Class.java:3894)
at java.base/java.lang.Class.getEnumConstants(Class.java:3869)
at Test.main(Test.java:21)
```
---------- BEGIN SOURCE ----------
/// BEGIN JAVA
import java.util.ArrayList;
import java.util.List;
final class Test {
public static void main(final String... args) throws Throwable {
final List<Throwable> errors = new ArrayList<>();
try {
final Object actual = BadEnum1.class.getEnumConstants();
if (actual != null) throw new AssertionError("Expected BadEnum1.class.getEnumConstants() to return null, got " + actual);
} catch (final Throwable t) {
errors.add(t);
}
try {
final Object actual = BadEnum2.class.getEnumConstants();
if (actual != null) throw new AssertionError("Expected BadEnum2.class.getEnumConstants() to return null, got " + actual);
} catch (final Throwable t) {
errors.add(t);
}
if (!errors.isEmpty()) {
final AssertionError err = new AssertionError(List.copyOf(errors));
errors.forEach(err::addSuppressed);
throw err;
}
}
}
/// END JAVA
/// BEGIN JASM
super final enum class BadEnum1
extends java/lang/Enum
version 52:0
{
Signature "Ljava/lang/Enum<LBadEnum1;>;";
private static final synthetic Field $VALUES:"[LBadEnum1;";
public Method values:"()[LBadEnum1;"
stack 1
{
getstatic Field $VALUES:"[LBadEnum1;";
invokevirtual Method "[LBadEnum1;".clone:"()Ljava/lang/Object;";
checkcast class "[LBadEnum1;";
areturn;
}
public static Method valueOf:"(Ljava/lang/String;)LBadEnum1;"
stack 2
0: #{name mandated}
{
ldc class BadEnum1;
aload_0;
invokestatic Method java/lang/Enum.valueOf:"(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;";
checkcast class BadEnum1;
areturn;
}
private Method "<init>":"(Ljava/lang/String;I)V":"()V"
stack 3
0: #{$enum$name synthetic}
1: #{$enum$ordinal synthetic}
{
aload_0;
aload_1;
iload_2;
invokespecial Method java/lang/Enum."<init>":"(Ljava/lang/String;I)V";
return;
}
private static synthetic Method $values:"()[LBadEnum1;"
stack 1
{
iconst_0;
anewarray class BadEnum1;
areturn;
}
static Method "<clinit>":"()V"
stack 1
{
invokestatic Method $values:"()[LBadEnum1;";
putstatic Field $VALUES:"[LBadEnum1;";
return;
}
}
super final enum class BadEnum2
extends java/lang/Enum
version 52:0
{
Signature "Ljava/lang/Enum<LBadEnum2;>;";
private static final synthetic Field $VALUES:"[LBadEnum2;";
public static Method values:"()Ljava/lang/Object;"
stack 2
{
new class java/lang/Object;
dup;
invokespecial Method java/lang/Object."<init>":"()V";
areturn;
}
public static Method valueOf:"(Ljava/lang/String;)LBadEnum2;"
stack 2
0: #{name mandated}
{
ldc class BadEnum2;
aload_0;
invokestatic Method java/lang/Enum.valueOf:"(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;";
checkcast class BadEnum2;
areturn;
}
private Method "<init>":"(Ljava/lang/String;I)V":"()V"
stack 3
0: #{$enum$name synthetic}
1: #{$enum$ordinal synthetic}
{
aload_0;
aload_1;
iload_2;
invokespecial Method java/lang/Enum."<init>":"(Ljava/lang/String;I)V";
return;
}
private static synthetic Method $values:"()[LBadEnum2;"
stack 1
{
iconst_0;
anewarray class BadEnum2;
areturn;
}
static Method "<clinit>":"()V"
stack 1
{
invokestatic Method $values:"()[LBadEnum2;";
putstatic Field $VALUES:"[LBadEnum2;";
return;
}
}
/// END JASM
---------- END SOURCE ----------
FREQUENCY : always