Exception 0Xc0000005 from Jni_Createjavavm (Jvm.Dll)

Exception 0xC0000005 from JNI_CreateJavaVM (jvm.dll)

JVM actively uses OS signals (or exceptions in Windows terminology) for its own purposes:

  • for implicit null pointer checks and stack overflow checks;
  • for safepoint polling;
  • for remote memory barriers;
  • etc.

SEGV (or exception 0xC0000005) is also generated intentionally on JVM startup to verify certain CPU/OS features. Some OSes or hypervisors had a bug that AVX registers are not restored after signal processing. Therefore, JVM needs to check whether this is the case (the source). So it generates an exception by writing to zero address and then handles it.

This is what happens in your case. And yes, it is normal.

Exception 0xC0000005 in jvm.dll when creating an instance via JNI NewObject

After days, I figured it out.

The constructor I am invoking expects a parameter. The type is long (Java) aka J (JNI Type Signature) aka jlong (corresponing C type). A C uintptr_t is compatible with a jlong.

On Linux, my uintptr_t is 8 bytes long, since I am in a amd64 environment with 64 bit applications. For Windows, the application was build in 32 bit. As a result uintptr_t is only 4 bytes long, but the JVM still expect a 8 byte jlong. However, NewObject is a variadic function, automatic promotion does not happen and type safety is not guaranteed.

login(uintptr_t connection, const char* username, …) {

jmethodID constructor = (*env)->GetMethodID(env, ps->class, "<init>", "(JLjava/lang/String;)V");
jstring jusername = (*env)->NewStringUTF(env, username);
jlong jconnection = connection;
jobject instance = (*env)->NewObject(env, ps->class, constructor, jconnection, jusername);

A simple cast to the correct type was the solution. I expect this pitfall to exist with CallVoidMethod or any of the Call*Method mentioned in the documentation, too.

Unable to use JNI when enabled from within Win32/MFC application

In the end, I figured this out. Apparently the JNI throws exceptions on startup by design to verify the environment it's running in. See Exception 0xC0000005 from JNI_CreateJavaVM (jvm.dll).

When I disabled the particular exception in Win32 exceptions in visual studio , it all works fine.

JNI_CreateJavaVM crash my program without any message or exception

Now I have turn to Load jvm.dll dynamicly:

typedef jint(JNICALL *pCreateJavaVM)(JavaVM **, void**, void *);

HINSTANCE hInstance = LoadLibrary(L"C:\\Program Files (x86)\\Java\\jre1.8.0_25\\bin\\client\\jvm.dll");
pCreateJavaVM CreateJavaVM = (pCreateJavaVM)GetProcAddress(hInstance, "JNI_CreateJavaVM");

options[0].optionString = "-Djava.class.path=.";
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;
status = CreateJavaVM(&jvm, (void**)&env, &vm_args);

And it works...I do not know why...

JNI_CreateJavaVM function method does not work and cannot be debugged

Classpath

There is a space between key and equal sign. The space must be removed.

char optionString[] = "-Djava.class.path =D:/Program Files/Java/jdk1.8.0_191/lib/";

Classpath value

The java.class.path value must point to the base directory where your compiled .class files are located.

It looks like you're not using a package name, then it's the directory where Main.class is located, so probably it should look something like this:

char optionString[] = "-Djava.class.path=c:/Users/name/MyJavaPrograms/classes";

Access violation

SEGV (or exception 0xC0000005) is also generated intentionally on JVM startup to verify certain CPU/OS features.

see this fine answer: https://stackoverflow.com/a/36258856

In Visual Studio, when the exception dialog is shown, simply turn off that it breaks there. This will prevent you from seeing it again the next time you start the program again.

Java

Just for the sake of completeness: the Java method should look like this:

public class Main {

public static void test(int num) {
System.out.println("Java: test called with '" + num + "'");
}

...

Visual Studio Configuration

The jvm.dll needs to be found. In Visual Studio under Configuration Properties/Debugging/Environment add PATH=%PATH%;<path-to-jdk>\bin\server

For later deployment you could think about putting the whole JRE into a subfolder of your application and reference it with a relative path.

Demo

Finally a brief demo (added a \n here printf("result=%d\n", res); to have a separate line):

Demo

0xC0000005: Access violation reading location 0x0000000000000000

You need to set options.extraInfo = 0;

I would do all of this for good measure. Defensive programming demands that everything is initialized.

#define CLEAR(x) memset(&x, 0, sizeof(x))
JavaVM *jvm(0);
JNIEnv *env(0);
JavaVMInitArgs vm_args;
CLEAR(vm_args);
JavaVMOption options;
CLEAR(options);

Note:

typedef struct JavaVMOption {
char *optionString;
void *extraInfo;
} JavaVMOption;

EDIT: None of this turned out to be the problem. The solution is in the comments -- the JVM is throwing access violation exceptions. They are caught and handled, but not before Visual Studio leads you to believe there is a problem.



Related Topics



Leave a reply



Submit