Misha reported the following RedefineClasses problem: Date: Mon, 07 Mar 2005 22:44:39 -0800 From: ###@###.### Subject: A problem with redefined java.lang.reflect.Method.invoke() Hi guys, I've recently discovered one more problem with method redefinition. Actually, it should have been there forever, it's just that the code that is problematic seems to be exercised quite rarely. It seems to me now that I've seen problems like this in the past, but they were in big apps like some App servers, that could just ignore such issues and proceed, or some such. The problem is that the VM initializes an internal variable, a methodOop for java.lang.reflect.Method.invoke() method early, and then uses it in some access rights checks. So if Method.invoke() is redefined, some (but not all) reflection calls may fail. Look at the code below that is from 1.4.2 JVM, vframe.cpp source file: // Step back n frames, skip and pseudo frames in between. // This function is used in Class.forName, Class.newInstance, Method.Invoke, // AccessController.doPrivileged. // // NOTE that in JDK 1.4 this has been exposed to Java as // sun.reflect.Reflection.getCallerClass(), which can be inlined. // Inlined versions must match this routine's logic. See, for example, // Parse::inline_native_Reflection_getCallerClass in // opto/library_call.cpp. void vframeStreamCommon::security_get_caller_frame(int depth) { while (depth-- > 0) { // skip Method.invoke() and auxiliary frames skip_method_invoke_and_aux_frames(); if (at_end()) return; // Skip real frame next(); } // skip Method.invoke() and auxiliary frames skip_method_invoke_and_aux_frames(); } void vframeStreamCommon::skip_method_invoke_and_aux_frames() { while (!at_end() && (/*method() == Universe::reflect_invoke_method() */ //We replace the above code with the check that works for redefined java.lang.reflect.Method.invoke() (method()->method_holder() == SystemDictionary::reflect_method_klass() && method()->name() == vmSymbols::invoke_name() && method()->signature() == vmSymbols::object_array_object_object_signature()) || (Universe::is_gte_jdk14x_version() && UseNewReflection && Klass::cast(method()->method_holder())->is_subclass_of(SystemDictionary::reflect_method_accessor_klass())))) { next(); } } The 'skip_method_invoke_and_aux_frames()' above already contains the original single code line commented out, and my fix for this problem (not sure it's the best possible one, but anyway, it works) in the next 3 lines. I have a JFluid test which demonstrates how the original VM code fails when Method.invoke() is redefined, and how this code works. It looks like in Mustang the problem is there as well, though I didn't look at its source code. No doubt a simpler test for this bug can be created. It just looks like the method that is invoked shouldn't be public and/or there should be some other non-obvious condition, which you can find out by looking at the relevant JDK code. Let me know if you would like me to do that. Let me know what you think about this issue. Misha ###@###.### 2005-03-08 19:18:11 GMT
|