8139164: JVM should throw ClassFormatError for non-void methods named <clinit>
authorhseigel
Tue, 10 Nov 2015 08:42:53 -0500
changeset 33799 77ebbd9b0ecc
parent 33796 8745ee8ac1db
child 33800 087307e61c0d
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
hotspot/src/share/vm/classfile/classFileParser.cpp
hotspot/src/share/vm/classfile/verifier.cpp
hotspot/test/runtime/classFileParserBug/BadInitMethod.java
hotspot/test/runtime/classFileParserBug/clinitArg.jasm
hotspot/test/runtime/classFileParserBug/clinitArg51.jasm
hotspot/test/runtime/classFileParserBug/clinitNonStatic.jasm
hotspot/test/runtime/classFileParserBug/ignoredClinit.jasm
hotspot/test/runtime/classFileParserBug/nonvoidClinit.jasm
--- 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