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