# HG changeset patch # User alanb # Date 1512665119 0 # Node ID 4fd79561f38f537ec70d4c02f44f3afbe7675d9c # Parent 309dbeb79657a8513364b63ac8894eab3d81f90b 8191867: Module attribute in 54.0+ class file cannot contains a requires java.base with ACC_TRANSITIVE or ACC_STATIC_PHASE Reviewed-by: psandoz, mchung diff -r 309dbeb79657 -r 4fd79561f38f src/java.base/share/classes/jdk/internal/module/ModuleInfo.java --- a/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java Tue Dec 05 16:34:03 2017 +0100 +++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java Thu Dec 07 16:45:19 2017 +0000 @@ -63,6 +63,9 @@ public final class ModuleInfo { + private final int JAVA_MIN_SUPPORTED_VERSION = 53; + private final int JAVA_MAX_SUPPORTED_VERSION = 54; + private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess(); @@ -188,8 +191,10 @@ int minor_version = in.readUnsignedShort(); int major_version = in.readUnsignedShort(); - if (major_version < 53) { - throw invalidModuleDescriptor("Must be >= 53.0"); + if (major_version < JAVA_MIN_SUPPORTED_VERSION || + major_version > JAVA_MAX_SUPPORTED_VERSION) { + throw invalidModuleDescriptor("Unsupported major.minor version " + + major_version + "." + minor_version); } ConstantPool cpool = new ConstantPool(in); @@ -245,7 +250,7 @@ switch (attribute_name) { case MODULE : - builder = readModuleAttribute(in, cpool); + builder = readModuleAttribute(in, cpool, major_version); break; case MODULE_PACKAGES : @@ -334,7 +339,7 @@ * Reads the Module attribute, returning the ModuleDescriptor.Builder to * build the corresponding ModuleDescriptor. */ - private Builder readModuleAttribute(DataInput in, ConstantPool cpool) + private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major) throws IOException { // module_name @@ -390,8 +395,21 @@ JLMA.requires(builder, mods, dn, vs); } - if (dn.equals("java.base")) + if (dn.equals("java.base")) { + if (major >= 54 + && (mods.contains(Requires.Modifier.TRANSITIVE) + || mods.contains(Requires.Modifier.STATIC))) { + String flagName; + if (mods.contains(Requires.Modifier.TRANSITIVE)) { + flagName = "ACC_TRANSITIVE"; + } else { + flagName = "ACC_STATIC_PHASE"; + } + throw invalidModuleDescriptor("The requires entry for java.base" + + " has " + flagName + " set"); + } requiresJavaBase = true; + } } if (mn.equals("java.base")) { if (requires_count > 0) { diff -r 309dbeb79657 -r 4fd79561f38f src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java --- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Tue Dec 05 16:34:03 2017 +0100 +++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Thu Dec 07 16:45:19 2017 +0000 @@ -80,7 +80,7 @@ */ private static byte[] toModuleInfo(ModuleDescriptor md, ModuleTarget target) { ClassWriter cw = new ClassWriter(0); - cw.visit(Opcodes.V9, ACC_MODULE, "module-info", null, null, null); + cw.visit(Opcodes.V10, ACC_MODULE, "module-info", null, null, null); int moduleFlags = md.modifiers().stream() .map(MODULE_MODS_TO_FLAGS::get) diff -r 309dbeb79657 -r 4fd79561f38f test/jdk/java/lang/module/ClassFileVersionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/module/ClassFileVersionsTest.java Thu Dec 07 16:45:19 2017 +0000 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @modules java.base/jdk.internal.module + * @run testng ClassFileVersionsTest + * @summary Test parsing of module-info.class with different class file versions + */ + +import java.lang.module.InvalidModuleDescriptorException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.nio.ByteBuffer; +import java.util.Set; + +import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; + +import jdk.internal.module.ModuleInfoWriter; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class ClassFileVersionsTest { + + // major, minor, modifiers for requires java.base + @DataProvider(name = "supported") + public Object[][] supported() { + return new Object[][]{ + { 53, 0, Set.of() }, // JDK 9 + { 53, 0, Set.of(STATIC) }, + { 53, 0, Set.of(TRANSITIVE) }, + { 53, 0, Set.of(STATIC, TRANSITIVE) }, + + { 54, 0, Set.of() }, // JDK 10 + }; + } + + // major, minor, modifiers for requires java.base + @DataProvider(name = "unsupported") + public Object[][] unsupported() { + return new Object[][]{ + { 50, 0, Set.of()}, // JDK 6 + { 51, 0, Set.of()}, // JDK 7 + { 52, 0, Set.of()}, // JDK 8 + + { 54, 0, Set.of(STATIC) }, // JDK 10 + { 54, 0, Set.of(TRANSITIVE) }, + { 54, 0, Set.of(STATIC, TRANSITIVE) }, + + { 55, 0, Set.of()}, // JDK 11 + }; + } + + @Test(dataProvider = "supported") + public void testSupported(int major, int minor, Set ms) { + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") + .requires(ms, "java.base") + .build(); + ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); + classFileVersion(bb, major, minor); + descriptor = ModuleDescriptor.read(bb); + assertEquals(descriptor.name(), "foo"); + } + + @Test(dataProvider = "unsupported", + expectedExceptions = InvalidModuleDescriptorException.class) + public void testUnsupported(int major, int minor, Set ms) { + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") + .requires(ms, "java.base") + .build(); + ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); + classFileVersion(bb, major, minor); + + // throws InvalidModuleDescriptorException + ModuleDescriptor.read(bb); + } + + private void classFileVersion(ByteBuffer bb, int major, int minor) { + bb.putShort(4, (short) minor); + bb.putShort(6, (short) major); + } +}