8058313: Mismatch of method descriptor and MethodParameters.parameters_count should cause MalformedParameterException
authoremc
Mon, 10 Nov 2014 16:45:46 -0500
changeset 27612 7201412afbd0
parent 27611 e8e7b0902deb
child 27613 f4773c0d8717
8058313: Mismatch of method descriptor and MethodParameters.parameters_count should cause MalformedParameterException Summary: Allow hotspot to store and report zero-length MethodParameters attribute data Reviewed-by: coleenp, jiangli
hotspot/src/share/vm/classfile/classFileParser.cpp
hotspot/src/share/vm/oops/constMethod.cpp
hotspot/src/share/vm/oops/constMethod.hpp
hotspot/src/share/vm/prims/jvm.cpp
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Mon Nov 10 10:13:10 2014 -0800
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Mon Nov 10 16:45:46 2014 -0500
@@ -2059,7 +2059,7 @@
   u2** localvariable_table_start;
   u2* localvariable_type_table_length;
   u2** localvariable_type_table_start;
-  u2 method_parameters_length = 0;
+  int method_parameters_length = -1;
   u1* method_parameters_data = NULL;
   bool method_parameters_seen = false;
   bool parsed_code_attribute = false;
@@ -2278,7 +2278,8 @@
       }
       method_parameters_seen = true;
       method_parameters_length = cfs->get_u1_fast();
-      if (method_attribute_length != (method_parameters_length * 4u) + 1u) {
+      const u2 real_length = (method_parameters_length * 4u) + 1u;
+      if (method_attribute_length != real_length) {
         classfile_parse_error(
           "Invalid MethodParameters method attribute length %u in class file",
           method_attribute_length, CHECK_(nullHandle));
@@ -2288,7 +2289,7 @@
       cfs->skip_u2_fast(method_parameters_length);
       // ignore this attribute if it cannot be reflected
       if (!SystemDictionary::Parameter_klass_loaded())
-        method_parameters_length = 0;
+        method_parameters_length = -1;
     } else if (method_attribute_name == vmSymbols::tag_synthetic()) {
       if (method_attribute_length != 0) {
         classfile_parse_error(
--- a/hotspot/src/share/vm/oops/constMethod.cpp	Mon Nov 10 10:13:10 2014 -0800
+++ b/hotspot/src/share/vm/oops/constMethod.cpp	Mon Nov 10 16:45:46 2014 -0500
@@ -116,7 +116,11 @@
   if (sizes->generic_signature_index() != 0) {
     extra_bytes += sizeof(u2);
   }
-  if (sizes->method_parameters_length() > 0) {
+  // This has to be a less-than-or-equal check, because we might be
+  // storing information from a zero-length MethodParameters
+  // attribute.  We have to store these, because in some cases, they
+  // cause the reflection API to throw a MalformedParametersException.
+  if (sizes->method_parameters_length() >= 0) {
     extra_bytes += sizeof(u2);
     extra_bytes += sizes->method_parameters_length() * sizeof(MethodParametersElement);
   }
@@ -237,7 +241,7 @@
     _flags |= _has_linenumber_table;
   if (sizes->generic_signature_index() != 0)
     _flags |= _has_generic_signature;
-  if (sizes->method_parameters_length() > 0)
+  if (sizes->method_parameters_length() >= 0)
     _flags |= _has_method_parameters;
   if (sizes->checked_exceptions_length() > 0)
     _flags |= _has_checked_exceptions;
@@ -272,7 +276,7 @@
   if (sizes->generic_signature_index() != 0)
     *(generic_signature_index_addr()) = sizes->generic_signature_index();
   // New data should probably go here.
-  if (sizes->method_parameters_length() > 0)
+  if (sizes->method_parameters_length() >= 0)
     *(method_parameters_length_addr()) = sizes->method_parameters_length();
   if (sizes->checked_exceptions_length() > 0)
     *(checked_exceptions_length_addr()) = sizes->checked_exceptions_length();
@@ -283,7 +287,7 @@
 }
 
 int ConstMethod::method_parameters_length() const {
-  return has_method_parameters() ? *(method_parameters_length_addr()) : 0;
+  return has_method_parameters() ? *(method_parameters_length_addr()) : -1;
 }
 
 MethodParametersElement* ConstMethod::method_parameters_start() const {
--- a/hotspot/src/share/vm/oops/constMethod.hpp	Mon Nov 10 10:13:10 2014 -0800
+++ b/hotspot/src/share/vm/oops/constMethod.hpp	Mon Nov 10 16:45:46 2014 -0500
@@ -372,6 +372,11 @@
   ExceptionTableElement* exception_table_start() const;
 
   // method parameters table
+
+  // This returns -1 if no parameters are present, a non-negative
+  // value otherwise.  Note: sometimes, there are 0-length parameters
+  // attributes that must be reported up to the reflection API all the
+  // same.
   int method_parameters_length() const;
   MethodParametersElement* method_parameters_start() const;
 
--- a/hotspot/src/share/vm/prims/jvm.cpp	Mon Nov 10 10:13:10 2014 -0800
+++ b/hotspot/src/share/vm/prims/jvm.cpp	Mon Nov 10 16:45:46 2014 -0500
@@ -1657,7 +1657,17 @@
   Handle reflected_method (THREAD, JNIHandles::resolve_non_null(method));
   const int num_params = mh->method_parameters_length();
 
-  if (0 != num_params) {
+  if (num_params < 0) {
+    // A -1 return value from method_parameters_length means there is no
+    // parameter data.  Return null to indicate this to the reflection
+    // API.
+    assert(num_params == -1, "num_params should be -1 if it is less than zero");
+    return (jobjectArray)NULL;
+  } else {
+    // Otherwise, we return something up to reflection, even if it is
+    // a zero-length array.  Why?  Because in some cases this can
+    // trigger a MalformedParametersException.
+
     // make sure all the symbols are properly formatted
     for (int i = 0; i < num_params; i++) {
       MethodParametersElement* params = mh->method_parameters_start();
@@ -1685,8 +1695,6 @@
       result->obj_at_put(i, param);
     }
     return (jobjectArray)JNIHandles::make_local(env, result());
-  } else {
-    return (jobjectArray)NULL;
   }
 }
 JVM_END