8139164: JVM should throw ClassFormatError for non-void methods named <clinit>
Summary: If method being parsed is named <clinit>, throw ClassFormatError if it is not void or has arguments, for class file version >= 51.
Reviewed-by: acorn, lfoltan
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Nov 10 04:37:35 2015 +0000
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Nov 10 08:42:53 2015 -0500
@@ -92,6 +92,7 @@
// Used for backward compatibility reasons:
// - to check NameAndType_info signatures more aggressively
+// - to disallow argument and require ACC_STATIC for <clinit> methods
#define JAVA_7_VERSION 51
// Extension method support.
@@ -1997,9 +1998,7 @@
} else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) {
flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
} else {
- // As of major_version 51, a method named <clinit> without ACC_STATIC is
- // just another method. So, do a normal method modifer check.
- verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
+ classfile_parse_error("Method <clinit> is not static in class file %s", CHECK_(nullHandle));
}
} else {
verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
@@ -5159,6 +5158,14 @@
return -2;
}
+ // Class initializers cannot have args for class format version >= 51.
+ if (name == vmSymbols::class_initializer_name() &&
+ signature != vmSymbols::void_method_signature() &&
+ _major_version >= JAVA_7_VERSION) {
+ throwIllegalSignature("Method", name, signature, CHECK_0);
+ return 0;
+ }
+
unsigned int args_size = 0;
char buf[fixed_buffer_size];
char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
@@ -5182,8 +5189,8 @@
// The first non-signature thing better be a ')'
if ((length > 0) && (*p++ == JVM_SIGNATURE_ENDFUNC)) {
length--;
- if (name == vmSymbols::object_initializer_name()) {
- // All "<init>" methods must return void
+ if (name->utf8_length() > 0 && name->byte_at(0) == '<') {
+ // All internal methods must return void
if ((length == 1) && (p[0] == JVM_SIGNATURE_VOID)) {
return args_size;
}
--- a/hotspot/src/share/vm/classfile/verifier.cpp Tue Nov 10 04:37:35 2015 +0000
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Tue Nov 10 08:42:53 2015 -0500
@@ -2846,7 +2846,7 @@
if (sig_stream.type() != T_VOID) {
if (method_name == vmSymbols::object_initializer_name()) {
// <init> method must have a void return type
- /* Unreachable? Class file parser verifies that <init> methods have
+ /* Unreachable? Class file parser verifies that methods with '<' have
* void return */
verify_error(ErrorContext::bad_code(bci),
"Return type must be void in <init> method");
--- a/hotspot/test/runtime/classFileParserBug/BadInitMethod.java Tue Nov 10 04:37:35 2015 +0000
+++ b/hotspot/test/runtime/classFileParserBug/BadInitMethod.java Tue Nov 10 08:42:53 2015 -0500
@@ -26,29 +26,59 @@
* @test
* @bug 8130669
* @summary VM prohibits <clinit> methods with return values
- * @compile ignoredClinit.jasm
+ * @compile nonvoidClinit.jasm
+ * @compile clinitNonStatic.jasm
+ * @compile clinitArg.jasm
+ * @compile clinitArg51.jasm
* @compile badInit.jasm
* @run main/othervm -Xverify:all BadInitMethod
*/
-// Test that a non-void <clinit> method does not cause an exception to be
-// thrown. But that a non-void <init> method causes a ClassFormatError
-// exception.
+// Test that non-void <clinit>, non-static <clinit>, and non-void
+// <init> methods cause ClassFormatException's to be thrown.
public class BadInitMethod {
public static void main(String args[]) throws Throwable {
System.out.println("Regression test for bug 8130669");
try {
- Class newClass = Class.forName("ignoredClinit");
- } catch (java.lang.Throwable e) {
- throw new RuntimeException("Unexpected exception: " + e.getMessage());
+ Class newClass = Class.forName("nonvoidClinit");
+ throw new RuntimeException(
+ "Expected ClassFormatError exception for non-void <clinit> not thrown");
+ } catch (java.lang.ClassFormatError e) {
+ System.out.println("Test BadInitMethod passed for non-void <clinit>");
+ }
+
+ try {
+ Class newClass = Class.forName("clinitNonStatic");
+ throw new RuntimeException(
+ "Expected ClassFormatError exception for non-static <clinit> not thrown");
+ } catch (java.lang.ClassFormatError e) {
+ System.out.println("Test BadInitMethod passed for non-static <clinit>");
+ }
+
+ // <clinit> with args is allowed in class file version < 51.
+ try {
+ Class newClass = Class.forName("clinitArg");
+ } catch (java.lang.ClassFormatError e) {
+ throw new RuntimeException(
+ "Unexpected ClassFormatError exception for <clinit> with argument in class file < 51");
+ }
+
+ // <clinit> with args is not allowed in class file version >= 51.
+ try {
+ Class newClass = Class.forName("clinitArg51");
+ throw new RuntimeException(
+ "Expected ClassFormatError exception for <clinit> with argument not thrown");
+ } catch (java.lang.ClassFormatError e) {
+ System.out.println("Test BadInitMethod passed for <clinit> with argument");
}
try {
Class newClass = Class.forName("badInit");
- throw new RuntimeException("Expected ClassFormatError exception not thrown");
+ throw new RuntimeException(
+ "Expected ClassFormatError exception for non-void <init> not thrown");
} catch (java.lang.ClassFormatError e) {
- System.out.println("Test BadInitMethod passed");
+ System.out.println("Test BadInitMethod passed for non-void <init>");
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/clinitArg.jasm Tue Nov 10 08:42:53 2015 -0500
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 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 class contains a <clinit> method with signature: (I)V. The JVM should
+// not throw ClassFormatError because methods named <clinit> that have arguments
+// are not illegal in class file versions < 51.
+
+public class clinitArg version 50:0
+{
+
+ public static Method "<clinit>":"(I)V"
+ stack 1 locals 1
+ {
+ iconst_0;
+ return;
+ }
+
+} // end Class clinitArg
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/clinitArg51.jasm Tue Nov 10 08:42:53 2015 -0500
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 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 class contains a <clinit> method with signature: (I)V. The JVM should
+// throw ClassFormatError because methods named <clinit> that have arguments
+// are illegal in class file version >= 51.
+
+public class clinitArg51 version 51:0
+{
+
+ public static Method "<clinit>":"(I)V"
+ stack 1 locals 1
+ {
+ iconst_0;
+ return;
+ }
+
+} // end Class clinitArg51
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/clinitNonStatic.jasm Tue Nov 10 08:42:53 2015 -0500
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 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 class contains a non-static <clinit> method. The JVM should
+// throw ClassFormatError because methods named <clinit> must be static
+// in class file versions >= 51.
+
+public class clinitNonStatic version 51:0
+{
+
+ public Method "<clinit>":"()V"
+ stack 1 locals 1
+ {
+ iconst_0;
+ return;
+ }
+
+} // end Class clinitNonStatic
--- a/hotspot/test/runtime/classFileParserBug/ignoredClinit.jasm Tue Nov 10 04:37:35 2015 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2015, 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 class contains a <clinit> method with signature: ()I. The JVM should
-// not complain about this because methods named <clinit> that have arguments
-// and/or are not void should be ignored by the JVM.
-
-public class ignoredClinit version 51:0
-{
-
- public static Method "<clinit>":"()I"
- stack 1 locals 1
- {
- iconst_0;
- ireturn;
- }
-
-} // end Class ignoredClinit
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/nonvoidClinit.jasm Tue Nov 10 08:42:53 2015 -0500
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 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 class contains a <clinit> method with signature: ()I. The JVM should
+// throw ClassFormatError because methods named <clinit> that are not void
+// are illegal.
+
+public class nonvoidClinit version 51:0
+{
+
+ public static Method "<clinit>":"()I"
+ stack 1 locals 1
+ {
+ iconst_0;
+ ireturn;
+ }
+
+} // end Class nonvoidClinit