-
Bug
-
Resolution: Duplicate
-
P4
-
23
-
Cause Known
-
generic
-
generic
A DESCRIPTION OF THE PROBLEM :
Currently, when `Utf8Entry::equalsString` is called with a `null` value, then it only sometimes throws `NullPointerException`.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached Java program.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
```
State.STRING: false
State.RAW: false
State.BYTE: false
State.CHAR: false
```
or
```
State.STRING: java.lang.NullPointerException
State.RAW: java.lang.NullPointerException
State.BYTE: java.lang.NullPointerException
State.CHAR: java.lang.NullPointerException
```
ACTUAL -
```
State.STRING: false
State.RAW: java.lang.NullPointerException
State.BYTE: java.lang.NullPointerException
State.CHAR: java.lang.NullPointerException
```
---------- BEGIN SOURCE ----------
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
import java.lang.classfile.*;
import java.lang.classfile.attribute.*;
import java.lang.classfile.constantpool.*;
import java.lang.constant.ClassDesc;
import java.util.List;
import java.util.Locale;
import static java.lang.classfile.ClassFile.*;
import static java.lang.constant.ConstantDescs.*;
import static java.util.Objects.requireNonNullElse;
public final class Utf8EntryEqualsStringTest {
record TestCase(
String label,
Utf8Entry entry
) implements Runnable {
@Override
public void run() {
Boolean result = null;
Exception ex = null;
try {
result = entry.equalsString(null);
} catch (final Exception e) {
ex = e;
}
System.out.printf(
Locale.ROOT,
"%-12s\t%s%n",
label,
requireNonNullElse(ex, result).toString()
);
}
}
private static final String State_STRING = "State.STRING";
private static final String State_RAW = "State.RAW";
private static final String State_BYTE = "State.BYTE";
private static final String State_CHAR = "State.CHAR";
public static final void main(final String... args) {
final var testCases = prepareUtf8Entries(ClassFile.of());
for (final var testCase : testCases) {
testCase.run();
}
}
private static final List<TestCase> prepareUtf8Entries(final ClassFile cf) {
final var cm = cf.parse(cf.build(ClassDesc.of(DEFAULT_NAME), cb -> {
withConstant(cb, State_RAW, "raw");
withConstant(cb, State_BYTE, "byte");
withConstant(cb, State_CHAR, "π (\u03C0)");
}));
Utf8Entry
stateString,
stateRaw = null,
stateByte = null,
stateChar = null;
for (final var field : cm.fields()) {
switch (field.fieldName().stringValue()) {
case State_RAW -> {
stateRaw = getStringConstantValue(field);
}
case State_BYTE -> {
stateByte = getStringConstantValue(field);
stateByte.length();
}
case State_CHAR -> {
stateChar = getStringConstantValue(field);
stateChar.length();
}
}
}
stateString = (Utf8Entry) AnnotationValue.ofString("string").constant();
return List.of(
new TestCase(State_STRING + ':', stateString),
new TestCase(State_RAW + ':', stateRaw),
new TestCase(State_BYTE + ':', stateByte),
new TestCase(State_CHAR + ':', stateChar)
);
}
private static final void withConstant(final ClassBuilder cb, final String name, final String value) {
cb.withField(name, CD_String, fb -> {
fb.withFlags(ACC_STATIC | ACC_FINAL);
fb.with(ConstantValueAttribute.of(value));
});
}
private static final Utf8Entry getStringConstantValue(final FieldModel field) {
var constantValueAttr = (ConstantValueAttribute) field.elementStream()
.filter(e -> e instanceof ConstantValueAttribute)
.reduce((_, _) -> { throw new IllegalStateException(field.toString()); })
.orElseThrow(() -> new IllegalArgumentException(field.toString()));
return ((StringEntry) constantValueAttr.constant()).utf8();
}
}
---------- END SOURCE ----------
FREQUENCY : always
Currently, when `Utf8Entry::equalsString` is called with a `null` value, then it only sometimes throws `NullPointerException`.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached Java program.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
```
State.STRING: false
State.RAW: false
State.BYTE: false
State.CHAR: false
```
or
```
State.STRING: java.lang.NullPointerException
State.RAW: java.lang.NullPointerException
State.BYTE: java.lang.NullPointerException
State.CHAR: java.lang.NullPointerException
```
ACTUAL -
```
State.STRING: false
State.RAW: java.lang.NullPointerException
State.BYTE: java.lang.NullPointerException
State.CHAR: java.lang.NullPointerException
```
---------- BEGIN SOURCE ----------
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
import java.lang.classfile.*;
import java.lang.classfile.attribute.*;
import java.lang.classfile.constantpool.*;
import java.lang.constant.ClassDesc;
import java.util.List;
import java.util.Locale;
import static java.lang.classfile.ClassFile.*;
import static java.lang.constant.ConstantDescs.*;
import static java.util.Objects.requireNonNullElse;
public final class Utf8EntryEqualsStringTest {
record TestCase(
String label,
Utf8Entry entry
) implements Runnable {
@Override
public void run() {
Boolean result = null;
Exception ex = null;
try {
result = entry.equalsString(null);
} catch (final Exception e) {
ex = e;
}
System.out.printf(
Locale.ROOT,
"%-12s\t%s%n",
label,
requireNonNullElse(ex, result).toString()
);
}
}
private static final String State_STRING = "State.STRING";
private static final String State_RAW = "State.RAW";
private static final String State_BYTE = "State.BYTE";
private static final String State_CHAR = "State.CHAR";
public static final void main(final String... args) {
final var testCases = prepareUtf8Entries(ClassFile.of());
for (final var testCase : testCases) {
testCase.run();
}
}
private static final List<TestCase> prepareUtf8Entries(final ClassFile cf) {
final var cm = cf.parse(cf.build(ClassDesc.of(DEFAULT_NAME), cb -> {
withConstant(cb, State_RAW, "raw");
withConstant(cb, State_BYTE, "byte");
withConstant(cb, State_CHAR, "π (\u03C0)");
}));
Utf8Entry
stateString,
stateRaw = null,
stateByte = null,
stateChar = null;
for (final var field : cm.fields()) {
switch (field.fieldName().stringValue()) {
case State_RAW -> {
stateRaw = getStringConstantValue(field);
}
case State_BYTE -> {
stateByte = getStringConstantValue(field);
stateByte.length();
}
case State_CHAR -> {
stateChar = getStringConstantValue(field);
stateChar.length();
}
}
}
stateString = (Utf8Entry) AnnotationValue.ofString("string").constant();
return List.of(
new TestCase(State_STRING + ':', stateString),
new TestCase(State_RAW + ':', stateRaw),
new TestCase(State_BYTE + ':', stateByte),
new TestCase(State_CHAR + ':', stateChar)
);
}
private static final void withConstant(final ClassBuilder cb, final String name, final String value) {
cb.withField(name, CD_String, fb -> {
fb.withFlags(ACC_STATIC | ACC_FINAL);
fb.with(ConstantValueAttribute.of(value));
});
}
private static final Utf8Entry getStringConstantValue(final FieldModel field) {
var constantValueAttr = (ConstantValueAttribute) field.elementStream()
.filter(e -> e instanceof ConstantValueAttribute)
.reduce((_, _) -> { throw new IllegalStateException(field.toString()); })
.orElseThrow(() -> new IllegalArgumentException(field.toString()));
return ((StringEntry) constantValueAttr.constant()).utf8();
}
}
---------- END SOURCE ----------
FREQUENCY : always
- duplicates
-
JDK-8317356 Fix missing null checks in the ClassFile API
-
- Resolved
-
- links to
-
Review(master) openjdk/jdk/20556