8139164: JVM should throw ClassFormatError for non-void methods named <clinit>

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
This commit is contained in:
Harold Seigel 2015-11-10 08:42:53 -05:00
parent fd47033053
commit 3756d55ee6
7 changed files with 173 additions and 19 deletions

View file

@ -92,6 +92,7 @@
// Used for backward compatibility reasons: // Used for backward compatibility reasons:
// - to check NameAndType_info signatures more aggressively // - to check NameAndType_info signatures more aggressively
// - to disallow argument and require ACC_STATIC for <clinit> methods
#define JAVA_7_VERSION 51 #define JAVA_7_VERSION 51
// Extension method support. // Extension method support.
@ -1997,9 +1998,7 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
} else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) { } else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) {
flags &= JVM_ACC_STATIC | JVM_ACC_STRICT; flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
} else { } else {
// As of major_version 51, a method named <clinit> without ACC_STATIC is classfile_parse_error("Method <clinit> is not static in class file %s", CHECK_(nullHandle));
// just another method. So, do a normal method modifer check.
verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
} }
} else { } else {
verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle)); verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
@ -5159,6 +5158,14 @@ int ClassFileParser::verify_legal_method_signature(Symbol* name, Symbol* signatu
return -2; 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; unsigned int args_size = 0;
char buf[fixed_buffer_size]; char buf[fixed_buffer_size];
char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
@ -5182,8 +5189,8 @@ int ClassFileParser::verify_legal_method_signature(Symbol* name, Symbol* signatu
// The first non-signature thing better be a ')' // The first non-signature thing better be a ')'
if ((length > 0) && (*p++ == JVM_SIGNATURE_ENDFUNC)) { if ((length > 0) && (*p++ == JVM_SIGNATURE_ENDFUNC)) {
length--; length--;
if (name == vmSymbols::object_initializer_name()) { if (name->utf8_length() > 0 && name->byte_at(0) == '<') {
// All "<init>" methods must return void // All internal methods must return void
if ((length == 1) && (p[0] == JVM_SIGNATURE_VOID)) { if ((length == 1) && (p[0] == JVM_SIGNATURE_VOID)) {
return args_size; return args_size;
} }

View file

@ -2846,7 +2846,7 @@ void ClassVerifier::verify_invoke_instructions(
if (sig_stream.type() != T_VOID) { if (sig_stream.type() != T_VOID) {
if (method_name == vmSymbols::object_initializer_name()) { if (method_name == vmSymbols::object_initializer_name()) {
// <init> method must have a void return type // <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 */ * void return */
verify_error(ErrorContext::bad_code(bci), verify_error(ErrorContext::bad_code(bci),
"Return type must be void in <init> method"); "Return type must be void in <init> method");

View file

@ -26,29 +26,59 @@
* @test * @test
* @bug 8130669 * @bug 8130669
* @summary VM prohibits <clinit> methods with return values * @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 * @compile badInit.jasm
* @run main/othervm -Xverify:all BadInitMethod * @run main/othervm -Xverify:all BadInitMethod
*/ */
// Test that a non-void <clinit> method does not cause an exception to be // Test that non-void <clinit>, non-static <clinit>, and non-void
// thrown. But that a non-void <init> method causes a ClassFormatError // <init> methods cause ClassFormatException's to be thrown.
// exception.
public class BadInitMethod { public class BadInitMethod {
public static void main(String args[]) throws Throwable { public static void main(String args[]) throws Throwable {
System.out.println("Regression test for bug 8130669"); System.out.println("Regression test for bug 8130669");
try { try {
Class newClass = Class.forName("ignoredClinit"); Class newClass = Class.forName("nonvoidClinit");
} catch (java.lang.Throwable e) { throw new RuntimeException(
throw new RuntimeException("Unexpected exception: " + e.getMessage()); "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 { try {
Class newClass = Class.forName("badInit"); 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) { } catch (java.lang.ClassFormatError e) {
System.out.println("Test BadInitMethod passed"); System.out.println("Test BadInitMethod passed for non-void <init>");
} }
} }
} }

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -23,10 +23,10 @@
*/ */
// This class contains a <clinit> method with signature: ()I. The JVM should // This class contains a <clinit> method with signature: ()I. The JVM should
// not complain about this because methods named <clinit> that have arguments // throw ClassFormatError because methods named <clinit> that are not void
// and/or are not void should be ignored by the JVM. // are illegal.
public class ignoredClinit version 51:0 public class nonvoidClinit version 51:0
{ {
public static Method "<clinit>":"()I" public static Method "<clinit>":"()I"
@ -36,4 +36,4 @@ public class ignoredClinit version 51:0
ireturn; ireturn;
} }
} // end Class ignoredClinit } // end Class nonvoidClinit