When using JNI to call an interpreted method who's jmethodID stems from an interface, the program receives a SIGSEGV. The signal handler in turn, goes into an endless unwind loop and the program appears to be hung. The sample program uses JNI to instantiate the "jvm", obtains the interface and implementation class, instantiates the latter and tries to call a method on it. First it uses a jmethodID obtained directly from the implementation class. That succeeds. Then, it uses the jmethodID it gets when obtaining the same method from the implemented interface. That fails. I know that sending a compressed tar file is against your policy, but you do need the .class files in order to reproduce this bug.
Created attachment 6109 [details] Sample code
I suspect this bug was fixed by this: 2004-04-14 Andrew Haley <aph@redhat.com> Bryce McKinlay <mckinlay@redhat.com> * java/lang/reflect/natMethod.cc (_Jv_CallAnyMethodA): Use _Jv_LookupInterfaceMethodIdx for calls to interfaces. * include/jvm.h (_Jv_CallAnyMethodA): Add new `iface' arg. * testsuite/libjava.lang/InvokeInterface.java: New file. * testsuite/libjava.lang/InvokeInterface.out: New file. This is only on cvs head, not in 3.4. I've set the target milestone to 3.4.1 to indicate that we should back-port this fix once 3.4.0 ships.
Confirmed.
Actually this isn't restricted to 3.4, the problem occurs on mainline as well.
Postponed until 3.4.2, unless someone fixes it sooner...
Postponed until GCC 3.4.3.
I'll look into the status of this for the 3.4 branch. AFAIK, Interface calls via JNI are still broken even on mainline. This patch only fixes it for reflection. Perhaps we should put the old, non-index based code back in for the 3.4 branch, and come up with a real fix for mainline.
Created attachment 7185 [details] Patch to add a test case
I looked at this a little, and wrote a test case that can be checked in whenever we're ready. This code is sort of a mess. A jmethodID doesn't have a pointer back to its declaring class, so we don't have an easy way to tell whether or not it came from an interface. We could search the "receiver" object's class hierarchy for the concrete method and use that, but this is inefficient. One question I have is why method->index is not -1 for a method declared in an interface. Perhaps declaring that this must be -1 for such methods is the simplest fix. Currently this is supposed to contain the dispatch index, but I don't see that we ever use that. Another approach would be to add a new flag to method->accflags indicating that it is an interface method. This is a hack, but would work. It would require going over bits of the runtime to ensure that we mask this bit out as appropriate, e.g. when adding Miranda methods to the concrete class hierarchy.
Postponed until GCC 3.4.4.
meth->index for an interface method should contain the IDT dispatch index for that method, which allows us to use fast interface dispatch (_Jv_LookupInterfaceMethodIdx) for Method.invoke() calls. Unfortunately, this index is useless without also knowing which interface the method belongs to, and as Tom points out, we do not currently have a way to get from a JNI jMethodID to the interface, hence this PR. Perhaps a special flag for interface methods would be the best fix in the short term, until we can somehow fix JNI to give us a class/interface from a jMethodID.
Subject: Bug 15001 CVSROOT: /cvs/gcc Module name: gcc Changes by: aph@gcc.gnu.org 2004-12-17 15:13:44 Modified files: libjava : ChangeLog libjava/java/lang/reflect: natMethod.cc Log message: 2004-12-10 Andrew Haley <aph@redhat.com> PR java/15001 * java/lang/reflect/natMethod.cc (_Jv_CallAnyMethodA): Look up abstract methods by name. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libjava/ChangeLog.diff?cvsroot=gcc&r1=1.3261&r2=1.3262 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libjava/java/lang/reflect/natMethod.cc.diff?cvsroot=gcc&r1=1.42&r2=1.43
Subject: Bug 15001 CVSROOT: /cvs/gcc Module name: gcc Changes by: tromey@gcc.gnu.org 2004-12-21 00:49:46 Modified files: libjava : ChangeLog Added files: libjava/testsuite/libjava.jni: iface.c iface.java iface.out Log message: PR java/15001 * testsuite/libjava.jni/iface.c: New file. * testsuite/libjava.jni/iface.out: New file. * testsuite/libjava.jni/iface.java: New file. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libjava/ChangeLog.diff?cvsroot=gcc&r1=1.3263&r2=1.3264 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libjava/testsuite/libjava.jni/iface.c.diff?cvsroot=gcc&r1=NONE&r2=1.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libjava/testsuite/libjava.jni/iface.java.diff?cvsroot=gcc&r1=NONE&r2=1.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libjava/testsuite/libjava.jni/iface.out.diff?cvsroot=gcc&r1=NONE&r2=1.1
Fix checked in.