From 3f5b896f93d599322f45301893b1de0351fab38a Mon Sep 17 00:00:00 2001 From: Theresa Mammarella Date: Tue, 12 Sep 2023 16:03:17 -0400 Subject: [PATCH] NullRestricted field throws NPE on null assignment in withfield Signed-off-by: Theresa Mammarella --- runtime/vm/BytecodeInterpreter.hpp | 10 +++++ .../lworld/ValhallaAttributeGenerator.java | 39 ++++++++++++++++++- .../test/lworld/ValhallaAttributeTests.java | 14 +++++-- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/runtime/vm/BytecodeInterpreter.hpp b/runtime/vm/BytecodeInterpreter.hpp index 4a5b0939cb9..918670affb4 100644 --- a/runtime/vm/BytecodeInterpreter.hpp +++ b/runtime/vm/BytecodeInterpreter.hpp @@ -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) { diff --git a/test/functional/Valhalla/src/org/openj9/test/lworld/ValhallaAttributeGenerator.java b/test/functional/Valhalla/src/org/openj9/test/lworld/ValhallaAttributeGenerator.java index 14aa8d83958..71c9d121f37 100644 --- a/test/functional/Valhalla/src/org/openj9/test/lworld/ValhallaAttributeGenerator.java +++ b/test/functional/Valhalla/src/org/openj9/test/lworld/ValhallaAttributeGenerator.java @@ -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. */ @@ -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. */ @@ -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, "", "()V", null, null); + mvInit.visitCode(); + mvInit.visitVarInsn(ALOAD, 0); + mvInit.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()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); } diff --git a/test/functional/Valhalla/src/org/openj9/test/lworld/ValhallaAttributeTests.java b/test/functional/Valhalla/src/org/openj9/test/lworld/ValhallaAttributeTests.java index d76e9b5b812..31875e5e42d 100644 --- a/test/functional/Valhalla/src/org/openj9/test/lworld/ValhallaAttributeTests.java +++ b/test/functional/Valhalla/src/org/openj9/test/lworld/ValhallaAttributeTests.java @@ -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(); } @@ -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) { @@ -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(); + } }