Skip to content

Commit

Permalink
Reinforce the check on the sealed classes in JEP397
Browse files Browse the repository at this point in the history
The change is to add more check on the sealed classes
specified in JEP397: Sealed Classes (Second Preview)

Related: eclipse-openj9#11273

Signed-off-by: Cheng Jin <jincheng@ca.ibm.com>
  • Loading branch information
Cheng Jin committed Mar 5, 2021
1 parent d780e8d commit 080ec44
Show file tree
Hide file tree
Showing 23 changed files with 859 additions and 2 deletions.
20 changes: 19 additions & 1 deletion runtime/nls/j9vm/j9vm.nls
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2000, 2020 IBM Corp. and others
# Copyright (c) 2000, 2021 IBM Corp. and others
#
# This program and the accompanying materials are made available under
# the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -2010,3 +2010,21 @@ J9NLS_VM_ERROR_BYTECODE_OBJECTREF_CANNOT_BE_VALUE_BASED.explanation=The class ha
J9NLS_VM_ERROR_BYTECODE_OBJECTREF_CANNOT_BE_VALUE_BASED.system_action=The JVM will throw an VirtualMachineError.
J9NLS_VM_ERROR_BYTECODE_OBJECTREF_CANNOT_BE_VALUE_BASED.user_response=Contact the provider of the classfile for a corrected version.
# END NON-TRANSLATABLE

# Message to use when class/interface is not in the same module as its sealed super class/interface
# argument 1 is the class name
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE=The class/interface %2$.*1$s is not in the same module as its sealed super class/interface.
# START NON-TRANSLATABLE
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE.explanation=The specified class must be in the same module as its sealed super class/interface.
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE.system_action=The JVM will throw an IncompatibleClassChangeError.
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE.user_response=Contact the provider of the classfile for a corrected version.
# END NON-TRANSLATABLE

# Message to use when non-public class/interface is not in the same package as its sealed super class/interface
# argument 1 is the class name
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE=The non-public class/interface %2$.*1$s is not in the same package as its sealed super class/interface.
# START NON-TRANSLATABLE
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE.explanation=The specified non-public class must be in the same package as its sealed super class/interface.
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE.system_action=The JVM will throw an IncompatibleClassChangeError.
J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE.user_response=Contact the provider of the classfile for a corrected version.
# END NON-TRANSLATABLE
60 changes: 60 additions & 0 deletions runtime/vm/createramclass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1614,6 +1614,48 @@ isClassPermittedBySealedSuper(J9ROMClass *superRomClass, U_8* className, U_16 cl
return result;
}

#if JAVA_SPEC_VERSION >= 16
/**
* JEP 397 (second preview): if super class/interface is sealed, IncompatibleClassChangeError is throw out
* if one of the following conditions is false:
* (1) the inheriting subclass is not in the same module as its super class/interface;
* (2) the inheriting subclass (non-public) is not in the same package as its super class/interface.
*
* @param vmThread the current VM thread
* @param superClass the super class/interface
* @param romClass the ROM class of subclass
* @param module the subclass's module
* @param packageID the subclass's package ID
* @return TRUE if subclass can legally inherit the super, FALSE otherwise.
*/
static VMINLINE BOOLEAN
isClassInTheSameModuleOrPckageAsSealedSuper(J9VMThread *vmThread, J9Class *superClass, J9ROMClass *romClass, J9Module *module, UDATA packageID)
{
if (J9ROMCLASS_IS_SEALED(superClass->romClass)) {
J9JavaVM *vm = vmThread->javaVM;
J9UTF8 *className = J9ROMCLASS_CLASSNAME(romClass);
bool classIsPublic = J9_ARE_ALL_BITS_SET(romClass->modifiers, J9AccPublic);
J9Module * superModule = superClass->module;

if (J9_IS_J9MODULE_UNNAMED(vm, superModule)) {
if (!classIsPublic && (packageID != superClass->packageID)) {
Trc_VM_CreateRAMClassFromROMClass_sealedSuperFromDifferentPackage(vmThread, superClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
setCurrentExceptionForBadClass(vmThread, className, J9VMCONSTANTPOOL_JAVALANGINCOMPATIBLECLASSCHANGEERROR, J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_PACKAGE);
return FALSE;
}
} else {
if (module != superModule) {
Trc_VM_CreateRAMClassFromROMClass_sealedSuperFromDifferentModule(vmThread, superClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
setCurrentExceptionForBadClass(vmThread, className, J9VMCONSTANTPOOL_JAVALANGINCOMPATIBLECLASSCHANGEERROR, J9NLS_VM_CLASS_LOADING_ERROR_SEALED_SUPER_IN_DIFFERENT_MODULE);
return FALSE;
}
}
}

return TRUE;
}
#endif /* JAVA_SPEC_VERSION >= 16 */

/**
* Attempts to recursively load (if necessary) the required superclass and
* interfaces for the class being loaded.
Expand Down Expand Up @@ -1684,6 +1726,15 @@ loadSuperClassAndInterfaces(J9VMThread *vmThread, J9ClassLoader *classLoader, J9
return FALSE;
}

#if JAVA_SPEC_VERSION >= 16
/* JEP 397 sealed classes: the current class must be in the same module as its superclass
* or in the same package as its superclass if non-public.
*/
if (!isClassInTheSameModuleOrPckageAsSealedSuper(vmThread, superclass, romClass, module, packageID)) {
return FALSE;
}
#endif /* JAVA_SPEC_VERSION >= 16 */

/* JEP 360 sealed classes: if superclass is sealed it must contain the romClass's name in its PermittedSubclasses attribute */
if (! isClassPermittedBySealedSuper(superclass->romClass, J9UTF8_DATA(className), J9UTF8_LENGTH(className))) {
Trc_VM_CreateRAMClassFromROMClass_classIsNotPermittedBySealedSuperclass(vmThread, superclass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
Expand Down Expand Up @@ -1751,6 +1802,15 @@ loadSuperClassAndInterfaces(J9VMThread *vmThread, J9ClassLoader *classLoader, J9
return FALSE;
}

#if JAVA_SPEC_VERSION >= 16
/* JEP 397 sealed classes: the current interface must be in the same module as its superinterface
* or in the same package as its superinterface if non-public.
*/
if (!isClassInTheSameModuleOrPckageAsSealedSuper(vmThread, interfaceClass, romClass, module, packageID)) {
return FALSE;
}
#endif /* JAVA_SPEC_VERSION >= 16 */

/* JEP 360 sealed classes: if superinterface is sealed it must contain the romClass's name in its PermittedSubclasses attribute */
if (! isClassPermittedBySealedSuper(interfaceClass->romClass, J9UTF8_DATA(className), J9UTF8_LENGTH(className))) {
Trc_VM_CreateRAMClassFromROMClass_classIsNotPermittedBySealedSuperinterface(vmThread, interfaceClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
Expand Down
3 changes: 3 additions & 0 deletions runtime/vm/j9vm.tdf
Original file line number Diff line number Diff line change
Expand Up @@ -874,3 +874,6 @@ TraceExit=Trc_VM_resolveInvokeDynamic_Exit Overhead=1 Level=3 Template="resolveI
TraceEntry=Trc_VM_sendResolveOpenJDKInvokeHandle_Entry Overhead=1 Level=2 Template="sendResolveOpenJDKInvokeHandle"
TraceExit=Trc_VM_sendResolveOpenJDKInvokeHandle_Exit Overhead=1 Level=2 Template="sendResolveOpenJDKInvokeHandle"
TraceEntry=Trc_VM_romClassLoadFromCookie_Entry2 Overhead=1 Level=3 Template="romClassLoadFromCookie vmStruct=%p clsNamePtr=%p clsName=%.*s romClassBytes=%p romClassLength=%d"

TraceException=Trc_VM_CreateRAMClassFromROMClass_sealedSuperFromDifferentModule Overhead=1 Level=1 Template="The sealed super class/interface (RAM class=%p) is not in the same module as %.*s"
TraceException=Trc_VM_CreateRAMClassFromROMClass_sealedSuperFromDifferentPackage Overhead=1 Level=1 Template="The sealed super class/interface (RAM class=%p) is not in the same package as %.*s (non-public)"
42 changes: 41 additions & 1 deletion test/functional/Java16andUp/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,46 @@
<!--Properties for this particular build-->
<property name="src" location="./src"/>
<property name="build" location="./bin"/>
<property name="module_src_root" location="./modules"/>
<property name="module_bin_root" location="./module_bin"/>
<property name="dest_module_bin" location="${DEST}/module_bin"/>
<property name="LIB" value="asm,testng,jcommander"/>
<import file="${TEST_ROOT}/TKG/scripts/getDependencies.xml"/>

<target name="init">
<mkdir dir="${DEST}" />
<mkdir dir="${build}"/>
</target>

<property name="MODULE_NAME_ROOT" value="org.openj9test.modularity" />
<property name="MODULE_PATH_ROOT" value="org/openj9/test/modularity"/>

<target name="compile_modules" depends="init" description="Create the base modules for the sealed classes">
<mkdir dir="${module_bin_root}" />
<copy file="${LIB_DIR}/testng.jar" todir="${module_bin_root}" />
<copy file="${LIB_DIR}/jcommander.jar" todir="${module_bin_root}" />
<copy file="${LIB_DIR}/asm.jar" todir="${module_bin_root}" />
<for list="moduleX,moduleY" param="mod">
<sequential>
<var name="module_src_dir" value="${module_src_root}/${MODULE_NAME_ROOT}.@{mod}" />
<var name="module_bin_dir" value="${module_bin_root}/${MODULE_NAME_ROOT}.@{mod}" />
<mkdir dir="${module_bin_dir}" />
<var name="modpath" value="--module-path ${module_bin_root} -d ${module_bin_dir}" />
<javac srcdir="${module_src_dir}" destdir="${module_bin_dir}" debug="true" fork="true" executable="${compiler.javac}" includeAntRuntime="false" encoding="ISO-8859-1">
<src path="${module_src_dir}" />
<compilerarg line='--add-exports java.base/jdk.internal.misc=ALL-UNNAMED' />
<compilerarg line='--enable-preview --source ${JDK_VERSION}' />
<compilerarg line="${modpath}" />
<classpath>
<pathelement location="${LIB_DIR}/testng.jar"/>
<pathelement location="${LIB_DIR}/jcommander.jar"/>
<pathelement location="${LIB_DIR}/asm.jar" />
<pathelement location="${build}" />
</classpath>
</javac>
</sequential>
</for>
</target>

<target name="compile" depends="init,getDependentLibs" description="Using java ${JDK_VERSION} to compile the source" >
<echo>Ant version is ${ant.version}</echo>
Expand All @@ -53,6 +86,7 @@

<javac srcdir="${src}" destdir="${build}" debug="true" fork="true" executable="${compiler.javac}" includeAntRuntime="false" encoding="ISO-8859-1">
<src path="${src}"/>
<exclude name="**/modules/**" />
<compilerarg line='--add-exports java.base/jdk.internal.misc=ALL-UNNAMED' />
<compilerarg line='--enable-preview --source ${JDK_VERSION}' />
<classpath>
Expand All @@ -64,10 +98,16 @@
</javac>
</target>

<target name="dist" depends="compile,dist_functional" description="generate the distribution" >
<target name="dist" depends="compile,dist_functional,compile_modules" description="generate the distribution" >
<echo>copy ${module_bin_root} to ${dest_module_bin}</echo>
<mkdir dir="${dest_module_bin}"/>
<copy todir="${dest_module_bin}">
<fileset dir="${module_bin_root}"/>
</copy>
<mkdir dir="${DEST}"/>
<jar jarfile="${DEST}/GeneralTest.jar" filesonly="true">
<fileset dir="${build}"/>
<fileset dir="${dest_module_bin}"/>
<fileset dir="${src}/../" includes="*.properties,*.xml"/>
</jar>
<copy todir="${DEST}">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

module org.openj9test.modularity.moduleX {
exports org.openj9.test.modularity.pkgA;
exports org.openj9.test.modularity.pkgD;
requires testng;
requires org.objectweb.asm;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.openj9.test.modularity.pkgA;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

import org.openj9.test.modularity.pkgD.SubClassPermitted1;

public sealed class SuperClassSealed permits TestSubclass1,SubClassPermitted1 {
}

/* Only used for the placeholder in the PermittedSubclasses attribute of the sealed superclass */
non-sealed class TestSubclass1 extends SuperClassSealed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.openj9.test.modularity.pkgA;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

import org.openj9.test.modularity.pkgD.SubClassPermitted2;

public sealed interface SuperInterfaceSealed permits TestSubclass2, SubClassPermitted2 {
}

/* Only used for the placeholder in the PermittedSubclasses attribute of the sealed superinterface */
non-sealed class TestSubclass2 implements SuperInterfaceSealed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.openj9.test.modularity.pkgD;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

import org.openj9.test.modularity.pkgA.SuperClassSealed;

public non-sealed class SubClassPermitted1 extends SuperClassSealed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.openj9.test.modularity.pkgD;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

import org.openj9.test.modularity.pkgA.SuperInterfaceSealed;
import org.openj9.test.modularity.pkgD.SuperClassInSamePkg;

public non-sealed class SubClassPermitted2 extends SuperClassInSamePkg implements SuperInterfaceSealed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.openj9.test.modularity.pkgD;

/*******************************************************************************
* Copyright (c) 2021, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

public class SuperClassInSamePkg {}
Loading

0 comments on commit 080ec44

Please sign in to comment.