Nested stack problem
James
kaffe@rufus.w3.org
Wed, 12 Jul 2000 20:23:39 -0500
This is a multi-part message in MIME format.
------=_NextPart_000_00A6_01BFEC3F.108464B0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Ok, I got around the longjmp/setjmp problem w/ Mozilla by building Kaffe
w/ --with-threads=unix-pthreads.
Things were moving along well when my OJI plugin was a huge monolithic
function. Now I am breaking it down so that it intiailizes in the correct
order (ie., a single JavaVM instance, multiple plugin instances).
The problem is that if I initialize the JVM within a nested function call,
and then attempt to use the JVM environment from a function that is nested
less than the call which initialized the JVM, the app segfaults.
Attached is a test program that illustrates the problem. It is a simple
sample (see test.cpp).
Here is the general flow I need to use in order to work in Mozilla:
Mozilla initializes the class factory (nsKaffeFactory) for the plugin. The
CreateInstance() method on this interface calls JNI_CreateJavaVM(...) and
caches the JNIEnv and JavaVM. CreateInstance is used by Mozilla to obtain a
reference to an object that can host an individual APPLET. So, Mozilla asks
nsKaffeFactory::CreateInstance for an nsKaffeApplet reference.
CreateInstance creates an nsKaffeApplet and provides the cached JNIEnv and
JavaVM values. CreateInstance then returns.
Later on, Mozilla decides it wants to initialize the APPLET. It then calls
Intialize, SetWindow, Start, etc. on the nsKaffeApplet. Any attempt to use
any methods on JNIEnv in any of these methods results in a segfault.
I have determined the problem is being caused as a result of the use of
JNIEnv being done above the point in the stack where CreateJavaVM was
called.
Does anyone know of a realistic work around? Sure, I could modify the main
mozilla source so that it launches the JVM at the base of the stack before
it does ANYTHING else. This would solve the problem, but would then create
a specific version of Mozilla just for Kaffe.
Ideas?
Thanks again,
James
ketrenoj@austin.rr.com
------=_NextPart_000_00A6_01BFEC3F.108464B0
Content-Type: application/octet-stream;
name="test.cpp"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="test.cpp"
/*=0A=
=0A=
I build this with:=0A=
=0A=
`gcc -o test test.cpp -lkaffevm -I/usr/local/include/kaffe`=0A=
=0A=
Then run:=0A=
=0A=
`test 0 0` =3D> SUCCESS=0A=
`test 0 100` =3D> SUCCESS=0A=
`test 100 100` =3D> SUCCESS=0A=
`test 100 0` =3D> FAILURE=0A=
`test 100 70` =3D> FAILURE=0A=
=0A=
etc.=0A=
=0A=
If you have a good fix for this, please email me:=0A=
=0A=
ketrenoj@austin.rr.com=0A=
=0A=
Thanks,=0A=
James=0A=
=0A=
*/=0A=
=0A=
=0A=
#include <stdlib.h>=0A=
#include <string.h>=0A=
#include <jni.h>=0A=
=0A=
JavaVM* m_JavaVM =3D NULL;=0A=
JNIEnv* m_JNIEnv =3D NULL;=0A=
JavaVMInitArgs vm_args;=0A=
=0A=
class CTest=0A=
{=0A=
public:=0A=
int NestInit(int i)=0A=
{=0A=
char test[100];=0A=
if (i =3D=3D 0)=0A=
return InitializeJVM();=0A=
return NestInit(i-1);=0A=
}=0A=
=0A=
int NestUse(int i)=0A=
{=0A=
char test[100];=0A=
if (i =3D=3D 0)=0A=
return UseJVM();=0A=
return NestUse(i-1);=0A=
}=0A=
=0A=
int InitializeJVM()=0A=
{=0A=
memset(&vm_args, '\0', sizeof(vm_args));=0A=
vm_args.version =3D 0x00010001;=0A=
=0A=
JNI_GetDefaultJavaVMInitArgs(&vm_args);=0A=
=0A=
vm_args.classpath =3D "/usr/local/share/kaffe/Klasses.jar";=0A=
vm_args.libraryhome =3D "/usr/local/lib/kaffe";=0A=
vm_args.classhome =3D "/usr/local/share/kaffe";=0A=
=0A=
if (JNI_CreateJavaVM(&m_JavaVM,=0A=
&m_JNIEnv,=0A=
&vm_args) < 0)=0A=
{=0A=
printf("0x%08lX - ...can't create Java VM.\n",=0A=
(long)this);=0A=
return 0;=0A=
}=0A=
=0A=
printf("0x%08lX - ...returning JavaVM =3D 0x%08lX, "=0A=
"JNIEnv =3D 0x%08lX\n",=0A=
(long)this, (long)m_JavaVM, (long)m_JNIEnv);=0A=
=0A=
return 1;=0A=
}=0A=
=0A=
int UseJVM()=0A=
{=0A=
=0A=
jclass java_lang_String =3D =
m_JNIEnv->FindClass("java/lang/String");=0A=
if (java_lang_String)=0A=
{=0A=
printf("0x%08lX - ...java/lang/String found.\n",=0A=
(long)this);=0A=
return 1;=0A=
}=0A=
=0A=
printf("0x%08lX - ...java/lang/String NOT found.\n",=0A=
(long)this);=0A=
=0A=
return 0;=0A=
}=0A=
};=0A=
=0A=
void main(int argc, char* argv[])=0A=
{=0A=
CTest Test;=0A=
int Init =3D 0;=0A=
int Use =3D 0;=0A=
=0A=
if (argc =3D=3D 3)=0A=
{=0A=
Use =3D atoi(argv[2]);=0A=
Init =3D atoi(argv[1]);=0A=
}=0A=
=0A=
if (argc =3D=3D 2)=0A=
Init =3D atoi(argv[1]);=0A=
=0A=
printf("> This will output saying it is returning the JavaVM.\n");=0A=
printf("> The call will be nested %d times with 100 bytes of =
local\n",=0A=
Init);=0A=
printf("> storage per nest.\n");=0A=
printf("> \n> Calling NestInit(%d)...\n\n", Init);=0A=
=0A=
Test.NestInit(Init);=0A=
=0A=
printf("\n> NestInit() Returned.\n>\n");=0A=
=0A=
printf("> Now attempting to use the returned JavaVM.\n");=0A=
printf("> This call will be nested %d times, also with 100 bytes =
of\n",=0A=
Use);=0A=
printf("> local storage per nest. If it doesn't say it found\n");=0A=
printf("> java/lang/String then things are broken. Providing a\n");=0A=
printf("> 'Use' nest where:\n");=0A=
printf("> Init - Use >=3D ~30 (ie., `test 1000 970`) will result in =
the\n");=0A=
printf("> failure.\n");=0A=
printf("> \n> Calling NestUse(%d)...\n\n", Use);=0A=
=0A=
Test.NestUse(Use);=0A=
=0A=
printf("\n> NestUse() Returned.\n> \n");=0A=
=0A=
printf("> Press ENTER to exit.\n");=0A=
getchar();=0A=
}=0A=
------=_NextPart_000_00A6_01BFEC3F.108464B0--