Access violation Exception in JNI VC++ code.

I have a main method in a VC++ class, in which i am creating\instantiating JVM.

In main method i am calling a method of my own utility class to create JVM.

I am cacheing JVM pointer in a private member variable.

I am using following code to create an object of class -

com/spss/java_client/core/script/COM/SpssCSApp

// getJvm function returns JavaVM interface pointer that was used while creating jvm

JavaVM*curr_jvm = getJvm();

JNIEnv* t_env;

curr_jvm->AttachCurrentThread((void **)&t_env, NULL);

if (t_env->ExceptionOccurred()){

t_env->ExceptionDescribe();

}

// Create an instance of ISpssApp

csAppClazz = t_env->FindClass("com/spss/java_client/core/script/COM/SpssCSApp");

if (t_env->ExceptionOccurred()){

t_env->ExceptionDescribe();

}

jmethodID mid = t_env->GetMethodID(csAppClazz,"<init>","()V");

if (t_env->ExceptionOccurred()){

t_env->ExceptionDescribe();

}

csApp = t_env->NewObject(csAppClazz, mid);

if (t_env->ExceptionOccurred()){

t_env->ExceptionDescribe();

}

After the call to t_env->FindClass my VC++ debug output shows following error -

First-chance exception at 0x00cb74bf in JNIEXE.exe: 0xC0000005: Access violation reading location 0x00000000

But the subsequent call to t_env->ExceptionOccurred returns false.

Also rest of the program runs fine.

I mean even if this exception is shown in debug output window, the creation of new objects in JVM doesn't fail.

So i am not able to detect what is the cause of this exception.

Can anybody help me out with this problem.

[2243 byte] By [atul_pa] at [2007-10-3 3:26:12]
# 1
You can start by checking return values from the methods.And if an exception is thrown you can not continue.
jschella at 2007-7-14 21:19:21 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 2

Thanks for reply jschell.

I have cheked the return values of all methods e.g. FindClass method. All methods returns valid objects. And also the exceptionOccured method returns false, that means exception has not been thrown in previous method call.

But still output window of VC++ debugger shows Access Violation message.

Can you eloborate more on your view?

atul_pa at 2007-7-14 21:19:21 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 3
Are you calling any other c code first? And that mean jni or not jni code?If yes then I suggest you might want to look at that for pointer errors.
jschella at 2007-7-14 21:19:21 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 4

Hi jschell , below you can find source code of my applicatrion.

1. Class JNIEXE.cpp defines main method.

2. Class SpssCsApp creates JVM and starts my java application by invoking main method of java class Driver.

3. Class JvmAppArgs and SpssLauncher are used to create JVM and start application.

4. I have written comments in startApplication method of SpssLauncher class that shows exactly where access violation occurs.

// JNIEXE.cpp : Defines the entry point for the console application.

#include "stdafx.h"

#include "SpssCSApp.h"

int main(int argc, char* argv[])

{

SpssCSApp objSPSS;

Sleep(5000);

SpssLauncher::getLauncher()->getJvm()->DetachCurrentThread();

SpssLauncher::getLauncher()->getJvm()->DestroyJavaVM();

}

// SpssCSApp.h : Declaration of the SpssCSApp.

#ifndef __SPSSCSAPP_H_

#define __SPSSCSAPP_H_

#include "SpssServers.h"

#include "SpssDocuments.h"

#include "SpssLauncher.h"

#include <jni.h>

class SpssCSApp

{

private:

SpssLauncher* launcher;

jobject csApp;

jclass csAppClazz;

public:

SpssCSApp();

};

#endif //__SPSSCSAPP_H_

// SpssCSApp.cpp : Implementation of SpssCSApp.

#include "stdafx.h"

#include "SpssCSApp.h"

#include "SpssLauncher.h"

#include <jni.h>

#define CLASSNAME "com/spss/java_client/ui/Driver"

SpssCSApp::SpssCSApp()

{

JvmAppArgs*svc_args;

SpssLauncher* jvmProvider;

jvmProvider = SpssLauncher::getLauncher();

jvmProvider->startJvm();

svc_args = new JvmAppArgs();

svc_args->setClass(CLASSNAME);

svc_args->setJvmService(jvmProvider);

jvmProvider->startApplication(svc_args);

JavaVM*curr_jvm = SpssLauncher::getLauncher()->getJvm();

JNIEnv* t_env;

curr_jvm->AttachCurrentThread((void **)&t_env, NULL);

if (t_env->ExceptionOccurred()) {

t_env->ExceptionDescribe();

}

// Create an instance of ISpssApp

csAppClazz = t_env->FindClass("com/spss/java_client/core/script/COM/SpssCSApp");

if (t_env->ExceptionOccurred()) {

t_env->ExceptionDescribe();

}

jmethodID mid = t_env->GetMethodID(csAppClazz, "<init>", "()V");

if (t_env->ExceptionOccurred()) {

t_env->ExceptionDescribe();

}

csApp = t_env->NewObject(csAppClazz, mid);

if (t_env->ExceptionOccurred()) {

t_env->ExceptionDescribe();

}

delete svc_args;

}

// JvmAppArgs.h : Declaration of the JvmAppArgs.

#include "stdafx.h"

#include <jni.h>

class SpssLauncher;

class JvmAppArgs

{

private:

int_argc;// # of args. to 'main' of server

char** _argv;// args to 'main' of server

char* _className;// class from which to invoke 'main'

int_cnt;// How many ptrs alloc'd for arglist

SpssLauncher* _jvmServices;

jobject csApp;

jclass csAppClazz;

void _freeArgList();

public:

JvmAppArgs();

// Getters and setters

char** getArgList();

char* getArg(int);

intgetArgListSize();

char* getClass();

SpssLauncher* getJvmService();

void setArg(char*);

void setArgList(char**);

void setClass(char*);

void setJvmService(SpssLauncher*);

void setCsApp(jobject cs){ csApp=cs;}

void setCsAppClazz(jclass cl){csAppClazz=cl;}

jobject getCsApp(){return csApp;}

jclass getCsAppClazz(){return csAppClazz;}

};

// JvmAppArgs.cpp : Class used to store arguments used for Jvm and Application startup.

#include "stdafx.h"

#include "JvmAppArgs.h"

#include <stdlib.h>

#include <malloc.h>

#include <string.h>

class SpssLauncher;

JvmAppArgs::JvmAppArgs()

{

_argc = 0;

_argv = NULL;

_cnt = 0;

}

char** JvmAppArgs::getArgList()

{

return _argv;

}

int JvmAppArgs::getArgListSize()

{

return _argc;

}

char* JvmAppArgs::getClass()

{

return _className;

}

void JvmAppArgs::setArgList(char** args)

{

if (_argv != NULL)

_freeArgList();

while (*args != NULL)

setArg(*args++);

}

void JvmAppArgs::setArg(char* arg)

{

#define ARGLIST_PGSZ10

if (_argc == _cnt) {

_argv = (char**) realloc(_argv, (ARGLIST_PGSZ + _argc) * sizeof(char*));

_cnt += ARGLIST_PGSZ;

}

_argv[_argc++] = arg;

}

void JvmAppArgs::setClass(char* name)

{

_className = name;

}

void JvmAppArgs::setJvmService(SpssLauncher* svc)

{

_jvmServices = svc;

}

SpssLauncher* JvmAppArgs::getJvmService()

{

return _jvmServices;

}

void JvmAppArgs::_freeArgList()

{

char** p = _argv;

while (*p) {

free(*p);

p++;

}

free(_argv);

_argc = 0;

_argv = NULL;

}

// SpssLauncher.h : Defines a Utility class SpssLauncher

#pragma once

#include "JvmAppArgs.h"

#include <jni.h>

#include <windows.h>

#include <process.h>

class SpssLauncher

{

private:

/* The virtual machine instance */

JavaVM*_jvm;

/*

* List of VM options to be specified when the VM is created.

*/

JavaVMOption *options;

int numOptions, maxOptions;

static SpssLauncher* launcherInstance;

void invokeMain(JNIEnv*, char*, jobjectArray);

jobjectArray makeArgsArray(JNIEnv*, int, char**);

public:

SpssLauncher() { numOptions = maxOptions = 0; options = NULL; }

~SpssLauncher();

int startJvm();

JavaVM*getJvm();

void startApplication(JvmAppArgs*);

void * MemAlloc(size_t size);

void AddOption(char *str, void *info);

void SetClassPath(char *s);

static SpssLauncher* getLauncher(void);

};

// SpssLauncher.cpp : Acts as a Utility class, Primarily used for initialization of Jvm and Application.

#if !defined(_MT)

#error _beginthreadex requires a multithreaded C run-time library.

#endif

#include "stdafx.h"

#include "SpssLauncher.h"

#include <windows.h>

#include <process.h>

#include <assert.h>

#include <jni.h>

#define PATH_SEPARATOR ';'

#define USER_CLASSPATH "E:\\java_client_main_branch\\java_client\\java_client\\bin;E:\\java_client_main_branch\\java_client\\java_client\\ui\\lib\\looks-1.3.2.jar;E:\\java_client_main_branch\\java_client\\java_client\\core\\lib\\xml-apis.jar;E:\\java_client_main_branch\\java_client\\java_client\\core\\lib\\xercesImpl.jar;E:\\java_client_main_branch\\java_client\\java_client\\core\\lib\\commons-codec-1.3.jar;E:\\java_client_main_branch\\java_client\\java_client\\core\\lib\\xmlrpc-2.0.1.jar;E:\\java_client_main_branch\\java_client\\java_client\\core\\lib\\Editor.jar;E:\\java_client_main_branch\\java_client\\java_client\\core\\lib\\viseditor\\visualization.jar;E:\\java_client_main_branch\\java_client\\java_client\\core\\lib\\viseditor\\jai_codec.jar"

#define JAVA_LIB_PATH_OPTION "-Djava.library.path=E:\\java_client_main_branch\\java_client"

#define APPLICATION_HOME_OPTION "-Dapplication.home=E:\\java_client_main_branch\\java_client"

/*

* Returns a pointer to a block of at least 'size' bytes of memory.

* Prints error message and exits if the memory could not be allocated.

*/

void *SpssLauncher::MemAlloc(size_t size)

{

void *p = malloc(size);

if (p == 0) {

perror("malloc");

exit(1);

}

return p;

}

/*

* Adds a new VM option with the given given name and value.

*/

void SpssLauncher::AddOption(char *str, void *info)

{

/*

* Expand options array if needed to accommodate at least one more

* VM option.

*/

if (numOptions >= maxOptions) {

if (options == 0) {

maxOptions = 4;

options = (JavaVMOption *)MemAlloc(maxOptions * sizeof(JavaVMOption));

} else {

JavaVMOption *tmp;

maxOptions *= 2;

tmp = (JavaVMOption *)MemAlloc(maxOptions * sizeof(JavaVMOption));

memcpy(tmp, options, numOptions * sizeof(JavaVMOption));

free(options);

options = tmp;

}

}

options[numOptions].optionString = str;

options[numOptions++].extraInfo = info;

}

void SpssLauncher::SetClassPath(char *s)

{

char *def = (char *)MemAlloc(strlen(s) + 40);

sprintf_s(def, (strlen(s) + 40), "-Djava.class.path=%s", s);

AddOption(def, NULL);

}

JavaVM* SpssLauncher::getJvm()

{

return _jvm;

}

int SpssLauncher::startJvm()

{

JavaVMInitArgs vm_args;

JNI_GetDefaultJavaVMInitArgs(&vm_args);

SetClassPath(USER_CLASSPATH);

AddOption(JAVA_LIB_PATH_OPTION, NULL);

AddOption(APPLICATION_HOME_OPTION, NULL);

vm_args.version = JNI_VERSION_1_2;

vm_args.options = options;

vm_args.nOptions = numOptions;

vm_args.ignoreUnrecognized = JNI_TRUE;

JNIEnv* env;

/* Create the Java VM */

if (JNI_CreateJavaVM(&_jvm, (void**)&env, &vm_args) < 0) {

fprintf(stderr, "could not create JVM\n");

free(options);

return 0;

}

free(options);

return 1;

}

SpssLauncher::~SpssLauncher()

{

//assert(_jvm != NULL);

//if(_jvm!=NULL)

_jvm->DestroyJavaVM();

}

/*

* Call the Java method 'public static void main'

*/

void SpssLauncher::invokeMain(JNIEnv* env, char* className, jobjectArray args)

{

jclass clazz = env->FindClass(className);

jmethodID mid = env->GetStaticMethodID(clazz,

"main","([Ljava/lang/String;)V");

env->CallStaticVoidMethod(clazz,mid,args);

}

jobjectArray SpssLauncher::makeArgsArray(JNIEnv* env, int argc, char** argv)

{

int i;

jstring jstr;

jclass clazz = env->FindClass("java/lang/String");

jobjectArray ja = env->NewObjectArray(argc,clazz,NULL);

for(i=0; i < argc; i++) {

jstr = env->NewStringUTF(argv[i]);

env->SetObjectArrayElement(ja,i,jstr);

}

return ja;

}

void SpssLauncher::startApplication(JvmAppArgs* args)

{

JvmAppArgs* appArgs = (JvmAppArgs*) args;

jobjectArrayja;

JNIEnv*t_env;

JavaVM*curr_jvm = SpssLauncher::getLauncher()->getJvm();

curr_jvm->GetEnv((void **)&t_env, JNI_VERSION_1_2);

Sleep(1000);

// UPTILL THIS ACCESS VOILATION HAS NOT BEEN OCCURED

ja = this->makeArgsArray(t_env,

appArgs->getArgListSize(),

appArgs->getArgList());

Sleep(1000);

this->invokeMain(t_env, appArgs->getClass(), ja);

Sleep(1000);

// AFTER THE ABOVE SLEEP CALL VC++ DEBUG OUTPUT WINDOW SHOWS ACCESS VIOLATION EXCEPTION

// BUT STILL THINGS WORK PROPERLY AFTER THIS

if ((*t_env).ExceptionOccurred()) {

(*t_env).ExceptionDescribe();

}

}

SpssLauncher * SpssLauncher::launcherInstance = NULL;

SpssLauncher* SpssLauncher::getLauncher(void)

{

if(launcherInstance == NULL)

{

launcherInstance = new SpssLauncher();

}

return launcherInstance;

}

atul_pa at 2007-7-14 21:19:21 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 5

I won't debug your code for you (I get paid to do that and that isn't why I post here.)

I will not that you must understand how pointers work in C++. And a brief look suggests that you might have problems.

For example what is the scope of 'options'?

And what makes you think that you can use memcopy on a 'JavaVMOption"?

jschella at 2007-7-14 21:19:21 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 6

I didn't mean that jschell. I posted my code just to give you a clear idea what I have done in my code.

Regarding scope of 'options' , its a private member variable of SpssLauncher class.

Also if I don't use memcopy for JavaVMOption and use simple code(As given below) to initialize options, I get the same error.

JavaVMOption* options=new JavaVMOption[3];

options[0].optionString = "-Djava.class.path=" USER_CLASSPATH;

options[1].optionString = JAVA_LIB_PATH_OPTION;

options[2].optionString = APPLICATION_HOME_OPTION;

//SetClassPath(USER_CLASSPATH);

//AddOption(JAVA_LIB_PATH_OPTION, NULL);

//AddOption(APPLICATION_HOME_OPTION, NULL);

vm_args.version = JNI_VERSION_1_4;

vm_args.options = options;

vm_args.nOptions = 3;

vm_args.ignoreUnrecognized = JNI_TRUE;

Also I wanted to know that whether I am making any mistake in creating the JVM.

atul_pa at 2007-7-14 21:19:21 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 7

My point with options is that it appears you are freeing it without knowing if it continues to be used.

My point with JavaVMOption is that you are copying as though it is simple (memory sequential) data structure. I suspect that is not the case.

Note that because of the above it makes me suspect that there could be other potential memory problems. I did not however check for other possibilities.

jschella at 2007-7-14 21:19:21 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 8

I tried by commenting the code to free options, but still same error is coming.

Also as I said in my prev reply I have also tried using JavaVMOption without memcopy.

Considering these issues I also revisited my code to find out similar problems and fix them.

But still same error is coming.

atul_pa at 2007-7-14 21:19:21 > top of Java-index,Java HotSpot Virtual Machine,Specifications...