8174725: JVM should throw NoClassDefFoundError if ACC_MODULE is set in access_flags
Summary: Check if ACC_MODULE is set, and if so, throw NoClassDefFoundError exception
Reviewed-by: dholmes, alanb, acorn, coleenp, lfoltan, gtriantafill
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Sat Feb 18 06:48:41 2017 +0000
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Feb 21 09:53:49 2017 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -3052,7 +3052,13 @@
"Class is both outer and inner class in class file %s", CHECK_0);
}
// Access flags
- jint flags = cfs->get_u2_fast() & RECOGNIZED_INNER_CLASS_MODIFIERS;
+ jint flags;
+ // JVM_ACC_MODULE is defined in JDK-9 and later.
+ if (_major_version >= JAVA_9_VERSION) {
+ flags = cfs->get_u2_fast() & (RECOGNIZED_INNER_CLASS_MODIFIERS | JVM_ACC_MODULE);
+ } else {
+ flags = cfs->get_u2_fast() & RECOGNIZED_INNER_CLASS_MODIFIERS;
+ }
if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
// Set abstract bit for old class files for backward compatibility
flags |= JVM_ACC_ABSTRACT;
@@ -4524,6 +4530,18 @@
// utility methods for format checking
void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const {
+ const bool is_module = (flags & JVM_ACC_MODULE) != 0;
+ assert(_major_version >= JAVA_9_VERSION || !is_module, "JVM_ACC_MODULE should not be set");
+ if (is_module) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_NoClassDefFoundError(),
+ "%s is not a class because access_flag ACC_MODULE is set",
+ _class_name->as_C_string());
+ return;
+ }
+
if (!_need_verify) { return; }
const bool is_interface = (flags & JVM_ACC_INTERFACE) != 0;
@@ -4532,14 +4550,12 @@
const bool is_super = (flags & JVM_ACC_SUPER) != 0;
const bool is_enum = (flags & JVM_ACC_ENUM) != 0;
const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0;
- const bool is_module_info= (flags & JVM_ACC_MODULE) != 0;
const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION;
if ((is_abstract && is_final) ||
(is_interface && !is_abstract) ||
(is_interface && major_gte_15 && (is_super || is_enum)) ||
- (!is_interface && major_gte_15 && is_annotation) ||
- is_module_info) {
+ (!is_interface && major_gte_15 && is_annotation)) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
@@ -5734,16 +5750,23 @@
stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len
// Access flags
- jint flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
+ jint flags;
+ // JVM_ACC_MODULE is defined in JDK-9 and later.
+ if (_major_version >= JAVA_9_VERSION) {
+ flags = stream->get_u2_fast() & (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_MODULE);
+ } else {
+ flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
+ }
if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
// Set abstract bit for old class files for backward compatibility
flags |= JVM_ACC_ABSTRACT;
}
+ verify_legal_class_modifiers(flags, CHECK);
+
_access_flags.set_flags(flags);
- verify_legal_class_modifiers((jint)_access_flags.as_int(), CHECK);
// This class and superclass
_this_class_index = stream->get_u2_fast();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/AccModuleTest.java Tue Feb 21 09:53:49 2017 -0500
@@ -0,0 +1,54 @@
+/*
+ * 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
+ * @bug 8174725
+ * @summary Throw NoClassDefFoundError if class access_flags have ACC_MODULE set
+ * @compile BadAccModule.jcod BadAccModInrClss.jcod
+ * @run main AccModuleTest
+ */
+
+// Test that classes with access_flags containing ACC_MODULE cause ClassDefNotFoundErrors.
+public class AccModuleTest {
+ public static void main(String args[]) throws Throwable {
+
+ System.out.println("Regression test for bug 8174725");
+ try {
+ Class newClass = Class.forName("BadAccModule");
+ throw new RuntimeException("Expected NoClassDefFoundError exception not thrown");
+ } catch (java.lang.NoClassDefFoundError e) {
+ if (!e.getMessage().contains("BadAccModule is not a class because access_flag ACC_MODULE is set")) {
+ throw new RuntimeException("Wrong NoClassDefFoundError exception for AccModuleTest: " + e.getMessage());
+ }
+ }
+ try {
+ Class newClass = Class.forName("BadAccModInrClss");
+ throw new RuntimeException("Expected NoClassDefFoundError exception not thrown");
+ } catch (java.lang.NoClassDefFoundError e) {
+ if (!e.getMessage().contains("BadAccModInrClss is not a class because access_flag ACC_MODULE is set")) {
+ throw new RuntimeException("Wrong NoClassDefFoundError exception for BadAccModInrClss: " + e.getMessage());
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/BadAccModInrClss.jcod Tue Feb 21 09:53:49 2017 -0500
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+/*
+ * This tests that a class in an InnerClasses attribute with ACC_MODULE set
+ * causes a NoClassDefFoundError exception to get thrown.
+ */
+
+class BadAccModInrClss {
+ 0xCAFEBABE;
+ 0; // minor version
+ 53; // version
+ [22] { // Constant Pool
+ ; // first element is empty
+ Field #3 #14; // #1 at 0x0A
+ Method #4 #15; // #2 at 0x0F
+ class #16; // #3 at 0x14
+ class #19; // #4 at 0x17
+ Utf8 "this$0"; // #5 at 0x1A
+ Utf8 "La;"; // #6 at 0x23
+ Utf8 "Synthetic"; // #7 at 0x29
+ Utf8 "<init>"; // #8 at 0x35
+ Utf8 "(Ljava/lang/Object;)V"; // #9 at 0x3E
+ Utf8 "Code"; // #10 at 0x56
+ Utf8 "LineNumberTable"; // #11 at 0x5D
+ Utf8 "SourceFile"; // #12 at 0x6F
+ Utf8 "a.java"; // #13 at 0x7C
+ NameAndType #5 #6; // #14 at 0x85
+ NameAndType #8 #20; // #15 at 0x8A
+ Utf8 "BadAccModInrClss"; // #16 at 0x8F
+ Utf8 "Loc"; // #17 at 0x9E
+ Utf8 "InnerClasses"; // #18 at 0xA4
+ Utf8 "java/lang/Object"; // #19 at 0xB3
+ Utf8 "()V"; // #20 at 0xC6
+ Utf8 "EnclosingMethod"; // #21 at 0xCC
+ } // Constant Pool
+
+ 0x0000; // access
+ #3;// this_cpx
+ #4;// super_cpx
+
+ [0] { // Interfaces
+ } // Interfaces
+
+ [1] { // fields
+ { // Member at 0xE8
+ 0x0000; // access
+ #5; // name_cpx
+ #6; // sig_cpx
+ [1] { // Attributes
+ Attr(#7, 0) { // Synthetic at 0xF0
+ } // end Synthetic
+ } // Attributes
+ } // Member
+ } // fields
+
+ [1] { // methods
+ { // Member at 0xF8
+ 0x0001; // access
+ #8; // name_cpx
+ #20; // sig_cpx
+ [1] { // Attributes
+ Attr(#10, 17) { // Code at 0x0100
+ 2; // max_stack
+ 2; // max_locals
+ Bytes[5]{
+ 0x2AB70002B1;
+ };
+ [0] { // Traps
+ } // end Traps
+ [0] { // Attributes
+ } // Attributes
+ } // end Code
+ } // Attributes
+ } // Member
+ } // methods
+
+ [3] { // Attributes
+ Attr(#12, 2) { // SourceFile at 0x0119
+ #13;
+ } // end SourceFile
+ ;
+ Attr(#18, 10) { // InnerClasses at 0x0121
+ [1] { // InnerClasses
+ #3 #0 #17 0x8000; // at 0x0131
+ }
+ } // end InnerClasses
+ ;
+ Attr(#21, 4) { // EnclosingMethod at 0x0131
+ 0x0004000F;
+ } // end EnclosingMethod
+ } // Attributes
+} // end class BadAccModInrClss
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/BadAccModule.jcod Tue Feb 21 09:53:49 2017 -0500
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ *
+ */
+
+// This is a .jcod file for a simple "Hello World" program with ACC_MODULE added
+// to its access_flags. (See line 67.) This should cause a NoClassDefFoundError
+// when loading the class.
+class BadAccModule {
+ 0xCAFEBABE;
+ 0; // minor version
+ 53; // version
+ [32] { // Constant Pool
+ ; // first element is empty
+ Method #6 #17; // #1 at 0x0A
+ Field #18 #19; // #2 at 0x0F
+ String #20; // #3 at 0x14
+ Method #21 #22; // #4 at 0x17
+ class #23; // #5 at 0x1C
+ class #24; // #6 at 0x1F
+ Utf8 "<init>"; // #7 at 0x22
+ Utf8 "()V"; // #8 at 0x2B
+ Utf8 "Code"; // #9 at 0x31
+ Utf8 "LineNumberTable"; // #10 at 0x38
+ Utf8 "main"; // #11 at 0x4A
+ Utf8 "([Ljava/lang/String;)V"; // #12 at 0x51
+ Utf8 "Exceptions"; // #13 at 0x6A
+ class #25; // #14 at 0x77
+ Utf8 "SourceFile"; // #15 at 0x7A
+ Utf8 "BadAccModule.java"; // #16 at 0x87
+ NameAndType #7 #8; // #17 at 0x9B
+ class #26; // #18 at 0xA0
+ NameAndType #27 #28; // #19 at 0xA3
+ Utf8 "Hello World"; // #20 at 0xA8
+ class #29; // #21 at 0xB6
+ NameAndType #30 #31; // #22 at 0xB9
+ Utf8 "BadAccModule"; // #23 at 0xBE
+ Utf8 "java/lang/Object"; // #24 at 0xCD
+ Utf8 "java/lang/Throwable"; // #25 at 0xE0
+ Utf8 "java/lang/System"; // #26 at 0xF6
+ Utf8 "out"; // #27 at 0x0109
+ Utf8 "Ljava/io/PrintStream;"; // #28 at 0x010F
+ Utf8 "java/io/PrintStream"; // #29 at 0x0127
+ Utf8 "println"; // #30 at 0x013D
+ Utf8 "(Ljava/lang/String;)V"; // #31 at 0x0147
+ } // Constant Pool
+
+ 0x8021; // access Added ACC_MODULE (0x8000) !!!
+ #5;// this_cpx
+ #6;// super_cpx
+
+ [0] { // Interfaces
+ } // Interfaces
+
+ [0] { // fields
+ } // fields
+
+ [2] { // methods
+ { // Member at 0x016B
+ 0x0001; // access
+ #7; // name_cpx
+ #8; // sig_cpx
+ [1] { // Attributes
+ Attr(#9, 29) { // Code at 0x0173
+ 1; // max_stack
+ 1; // max_locals
+ Bytes[5]{
+ 0x2AB70001B1;
+ };
+ [0] { // Traps
+ } // end Traps
+ [1] { // Attributes
+ Attr(#10, 6) { // LineNumberTable at 0x018A
+ [1] { // LineNumberTable
+ 0 1; // at 0x0196
+ }
+ } // end LineNumberTable
+ } // Attributes
+ } // end Code
+ } // Attributes
+ } // Member
+ ;
+ { // Member at 0x0196
+ 0x0009; // access
+ #11; // name_cpx
+ #12; // sig_cpx
+ [2] { // Attributes
+ Attr(#9, 37) { // Code at 0x019E
+ 2; // max_stack
+ 1; // max_locals
+ Bytes[9]{
+ 0xB200021203B60004;
+ 0xB1;
+ };
+ [0] { // Traps
+ } // end Traps
+ [1] { // Attributes
+ Attr(#10, 10) { // LineNumberTable at 0x01B9
+ [2] { // LineNumberTable
+ 0 4; // at 0x01C5
+ 8 5; // at 0x01C9
+ }
+ } // end LineNumberTable
+ } // Attributes
+ } // end Code
+ ;
+ Attr(#13, 4) { // Exceptions at 0x01C9
+ [1] { // Exceptions
+ #14; // at 0x01D3
+ }
+ } // end Exceptions
+ } // Attributes
+ } // Member
+ } // methods
+
+ [1] { // Attributes
+ Attr(#15, 2) { // SourceFile at 0x01D5
+ #16;
+ } // end SourceFile
+ } // Attributes
+} // end class BadAccModule
--- a/hotspot/test/runtime/modules/acc_module.jcod Sat Feb 18 06:48:41 2017 +0000
+++ b/hotspot/test/runtime/modules/acc_module.jcod Tue Feb 21 09:53:49 2017 -0500
@@ -23,7 +23,8 @@
/*
* This class consists of the following java code, but has an illegal class
- * access_flags value of 0x8000, that should be ignored by the JVM.
+ * access_flags value of 0x8000, that should be ignored by the JVM because
+ * the class file version is < 53.
*
* public class acc_module {
* public static void main(String[] args) {