Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NullRestricted field throws NPE on null assignment in withfield #18130

Merged
merged 1 commit into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions runtime/vm/BytecodeInterpreter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9703,6 +9703,16 @@ class INTERPRETER_CLASS
goto done;
}

#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
if (J9_ARE_ALL_BITS_SET(flags, J9FieldFlagIsNullRestricted)) {
j9object_t valueref = *(j9object_t*)_sp;
if (NULL == valueref) {
rc = THROW_NPE;
goto done;
}
}
#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */

/* need to zero memset the memory so padding bytes are zeroed for memcmp-like comparisons */
copyObjectRef = VM_ValueTypeHelpers::cloneValueType(_currentThread, _objectAccessBarrier, _objectAllocate, objectRefClass, originalObjectRef, true);
if (NULL == copyObjectRef) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public static Class<?> generateNullRestrictedAttributeInArrayField(String classN
return generator.defineClass(className, classBytes, 0, classBytes.length);
}

public static Class<?> generateStaticNullRestrictedFieldAssignedToNull(String className, String fieldClassName) {
public static Class<?> generatePutStaticNullToNullRestrictedField(String className, String fieldClassName) {
String fieldName = "field";

/* Generate field class - value class with ImplicitCreation attribute and ACC_DEFAULT flag set. */
Expand Down Expand Up @@ -126,7 +126,7 @@ public static Class<?> generateStaticNullRestrictedFieldAssignedToNull(String cl
return generator.defineClass(className, classBytes, 0, classBytes.length);
}

public static Class<?> generateInstanceNullRestrictedFieldAssignedToNull(String className, String fieldClassName) {
public static Class<?> generatePutFieldNullToNullRestrictedField(String className, String fieldClassName) {
String fieldName = "field";

/* Generate field class - value class with ImplicitCreation attribute and ACC_DEFAULT flag set. */
Expand Down Expand Up @@ -158,6 +158,41 @@ public static Class<?> generateInstanceNullRestrictedFieldAssignedToNull(String
return generator.defineClass(className, classBytes, 0, classBytes.length);
}

public static Class<?> generateWithFieldStoreNullToNullRestrictedField(String className, String fieldClassName) {
String fieldName = "field";

/* Generate field class - value class with ImplicitCreation attribute and ACC_DEFAULT flag set. */
byte[] fieldClassBytes = generateClass(fieldClassName, ACC_PUBLIC + ACC_FINAL + ValhallaUtils.ACC_VALUE_TYPE,
new Attribute[] {new ImplicitCreationAttribute(ValhallaUtils.ACC_DEFAULT)});
Class<?> fieldClass = generator.defineClass(fieldClassName, fieldClassBytes, 0, fieldClassBytes.length);

ClassWriter classWriter = new ClassWriter(0);
classWriter.visit(ValhallaUtils.CLASS_FILE_MAJOR_VERSION, ACC_PUBLIC + ValhallaUtils.ACC_IDENTITY, className, null, "java/lang/Object", null);

/* instance field of previously generated field class with NullRestrictd attribute */
FieldVisitor fieldVisitor = classWriter.visitField(ACC_PUBLIC, fieldName, fieldClass.descriptorString(), null, null);
fieldVisitor.visitAttribute(new NullRestrictedAttribute());

MethodVisitor mvInit = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mvInit.visitCode();
mvInit.visitVarInsn(ALOAD, 0);
mvInit.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mvInit.visitVarInsn(ALOAD, 0);
mvInit.visitTypeInsn(ValhallaUtils.ACONST_INIT, fieldClass.descriptorString());
mvInit.visitFieldInsn(PUTFIELD, className, fieldName, fieldClass.descriptorString());
mvInit.visitVarInsn(ALOAD, 0);
mvInit.visitFieldInsn(GETFIELD, className, fieldName, fieldClass.descriptorString());
mvInit.visitInsn(ACONST_NULL);
mvInit.visitFieldInsn(ValhallaUtils.WITHFIELD, className, fieldName, fieldClass.descriptorString());
mvInit.visitInsn(RETURN);
mvInit.visitMaxs(2, 1);
mvInit.visitEnd();

classWriter.visitEnd();
byte[] classBytes = classWriter.toByteArray();
return generator.defineClass(className, classBytes, 0, classBytes.length);
}

public static Class<?> findLoadedTestClass(String name) {
return generator.findLoadedClass(name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ static public void testNullRestrictedNotAllowedInArrayTypeField() throws Throwab

/* Instance field with NullRestricted attribute cannot be set to null. */
@Test(expectedExceptions = java.lang.NullPointerException.class)
static public void testNullRestrictedInstanceFieldCannotBeAssignedNull() throws Throwable {
Class<?> c = ValhallaAttributeGenerator.generateInstanceNullRestrictedFieldAssignedToNull("TestNullRestrictedInstanceFieldCannotBeAssignedNull", "TestNullRestrictedInstanceFieldCannotBeAssignedNullField");
static public void testPutFieldNullToNullRestrictedField() throws Throwable {
Class<?> c = ValhallaAttributeGenerator.generatePutFieldNullToNullRestrictedField("TestPutFieldNullToNullRestrictedField", "TestPutFieldNullToNullRestrictedFieldField");
c.newInstance();
}

Expand All @@ -117,9 +117,9 @@ static public void testNullRestrictedInstanceFieldCannotBeAssignedNull() throws
* Since value fields are implicitly final this will always be the case.
*/
@Test
static public void testNullRestrictedStaticFieldCannotBeAssignedNull() throws Throwable {
static public void testPutStaticNullToNullRestrictedField() throws Throwable {
try {
Class<?> c = ValhallaAttributeGenerator.generateStaticNullRestrictedFieldAssignedToNull("testNullRestrictedStaticFieldCannotBeAssignedNull", "testNullRestrictedStaticFieldCannotBeAssignedNullField");
Class<?> c = ValhallaAttributeGenerator.generatePutStaticNullToNullRestrictedField("TestPutStaticNullToNullRestrictedField", "TestPutStaticNullToNullRestrictedFieldField");
c.newInstance();
} catch(java.lang.ExceptionInInitializerError e) {
if (e.getCause() instanceof NullPointerException) {
Expand All @@ -129,4 +129,10 @@ static public void testNullRestrictedStaticFieldCannotBeAssignedNull() throws Th
}
Assert.fail("Test expected a NullPointerException wrapped in ExceptionInInitializerError.");
}

@Test(expectedExceptions = java.lang.NullPointerException.class)
static public void testWithFieldStoreNullToNullRestrictedField() throws Throwable {
Class<?> c = ValhallaAttributeGenerator.generateWithFieldStoreNullToNullRestrictedField("TestWithFieldStoreNullToNullRestrictedField", "TestWithFieldStoreNullToNullRestrictedFieldField");
c.newInstance();
}
}