Skip to Main Content

Java HotSpot Virtual Machine

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

JVM Crash When Using JNI and COM

843829Jan 5 2010 — edited Jan 7 2010
I'm trying to call a DLL compiled from VB6 source code that I do not have access to. The VB6 code simply retrieves data from a DB2 database using ADO and my client code grabs that data and marshals it to my Java code. I'm attempting to achieve this using JNI and COM (without a third-party bridge). It works 75% of the time, but the other 25% of the time, the JVM crashes with the usual Hotspot crash log containing an access violation exception. However, I don't know what in my C++ code (VC++ 8) could be causing this except for passing a "wild" pointer to the code lying underneath the COM object interface. If that is the case, I don't know how I am doing that.

The Java code that is calling my native method is running on Tomcat 5.5.25 and just to be safe, I am not allowing multiple threads to concurrently call the method in my JNI DLL (though I realize that this will kill performance). Once I can get past this problem, I'll do the COM interfacing on a worker thread in my native code so I don't screw up CoInitialize and CoUninitialize calls in the case the same thread is concurrently executing multiple calls to my native code.

I've noticed that in most cases, the JVM crashes during my call to the pClsAccount->OpenConnection method. However, my DLL isn't what is listed on the top of the call stack, which is why I suspect the passing of a wild pointer, though I'm just taking a guess at that. Does anyone have an idea as to what's going on ?

JNIEXPORT jobject JNICALL Java_CustomerInfo_nGetCustomerAccountInfo(JNIEnv *env, jobject customerInfo, jstring accountNumber, jstring iniFileName)

{

jboolean isCopy;

// Account info class and instance to be instantiated

jclass accountInfoCls = NULL;

jobject accountInfoObj = NULL;

// The constructor ID of the accountInfoCls

jmethodID ctorID = NULL;

// Pointer to the interface for the ClsAccount COM object

_clsAccount *pClsAccount = NULL;

HRESULT hr;

BSTR bstrIniFileName(L"");

try

{

const char *nativeAccountNumber = NULL;



if (accountNumber != NULL)

{

nativeAccountNumber = env->GetStringUTFChars(accountNumber, &isCopy);

}

else

{

jclass newExcCls;

env->ExceptionDescribe();

env->ExceptionClear();

newExcCls = env->FindClass("java/lang/IllegalArgumentException");

env->ThrowNew(newExcCls, "accountNumber passed in was null !");

return NULL;

}

// Initialization

variantt varConnectionSucceeded = variantt(false);

variantt varGetAccountInfoSucceeded = variantt(false);

variantt varAccountNumber = variantt(nativeAccountNumber);

bstrt bstrLastPaymentDate = bstrt();

bstrt bstrLastErrorMessage = bstrt();

bstrt bstrLastErrorNumber = bstrt();

jlong jTotalDue = NULL;

jlong jEstablishedDueDay = NULL;

jlong jLastPaymentAmount = NULL;

jstring jLastPaymentDate = NULL;

jstring jLastErrorMessage = NULL;

jstring jLastErrorNumber = NULL;

jthrowable jException = NULL;

const char *chLastPaymentDate = NULL;

const char *chLastErrorMessage = NULL;

const char *chLastErrorNumber = NULL;

long long totalDue;

long long lastPaymentAmount;

long establishedDueDateDay;

//Convert string from Java string to C string to VB string

const char *nativeIniFileName = NULL;

if (iniFileName != NULL)

{

nativeIniFileName = env->GetStringUTFChars(iniFileName, &isCopy);

}

else

{

jclass newExcCls;

env->ExceptionDescribe();

env->ExceptionClear();

newExcCls = env->FindClass("java/lang/IllegalArgumentException");

env->ThrowNew(newExcCls, "iniFileName passed in was null");

return NULL;

}

bstrIniFileName = comutil::ConvertStringToBSTR(nativeIniFileName);

CoInitialize(NULL);

// Create an instance of the COClass with the interface over it

hr = CoCreateInstance(__uuidof(clsAccount), NULL, CLSCTX_INPROC_SERVER, __uuidof(_clsAccount), (void **)&pClsAccount);

if (hr == S_OK)

{

varConnectionSucceeded.boolVal = pClsAccount->OpenConnection(&bstrIniFileName);

 

if (varConnectionSucceeded.boolVal == -1)

{

varGetAccountInfoSucceeded.boolVal = pClsAccount->GetAccountPaymentInformation(&(varAccountNumber.GetVARIANT()));

env->ReleaseStringUTFChars(accountNumber, nativeAccountNumber);

// Extract all available account information from the ClsAccount object

if (varGetAccountInfoSucceeded.boolVal == -1)

{

totalDue = pClsAccount->TotalDue.int64;

establishedDueDateDay = pClsAccount->EstablishedDueDateDay;

lastPaymentAmount = pClsAccount->LastPaymentAmount.int64;

bstrLastPaymentDate = pClsAccount->LastPaymentDate;

chLastPaymentDate = comutil::ConvertBSTRToString(bstrLastPaymentDate.GetBSTR());

jTotalDue = (jlong)totalDue;

jEstablishedDueDay = (jlong)establishedDueDateDay;

jLastPaymentAmount = (jlong)lastPaymentAmount;

jLastPaymentDate = env->NewStringUTF(chLastPaymentDate);

delete[] chLastPaymentDate;

}

pClsAccount->CloseConnection();

}

// Populate error fields if any errors occur

bstrLastErrorMessage = pClsAccount->LastErrMessage;

chLastErrorMessage = comutil::ConvertBSTRToString(bstrLastErrorMessage.GetBSTR());

bstrLastErrorNumber = pClsAccount->LastErrNumber;

chLastErrorNumber = comutil::ConvertBSTRToString(bstrLastErrorNumber.GetBSTR());

jLastErrorMessage = env->NewStringUTF(chLastErrorMessage);

jLastErrorNumber = env->NewStringUTF(chLastErrorNumber);

delete[] chLastErrorMessage;

delete[] chLastErrorNumber;

const char* clsName = "com/nuance/merchantsmutual/businessentities/CustomerAccountInfo";

// Find the Java class and the ID of its constructor

accountInfoCls = env->FindClass(clsName);

ctorID = env->GetMethodID(accountInfoCls, "<init>", "(JJJLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");

jException = env->ExceptionOccurred();

if (jException != NULL)

{

env->ExceptionDescribe();

env->ExceptionClear();

}

//Release all resources associated with the ClsAccount instance

pClsAccount->Release();

//Instantiate the class with the given parameters

accountInfoObj = env->NewObject(accountInfoCls, ctorID, jTotalDue, jEstablishedDueDay, jLastPaymentAmount, jLastPaymentDate, jLastErrorMessage, jLastErrorNumber);

jException = env->ExceptionOccurred();

if (jException != NULL)

{

env->ExceptionDescribe();

env->ExceptionClear();

}

}

else if (hr == REGDB_E_CLASSNOTREG)

{

cout << "COM class not registered" << endl;

}

else if ( hr == CLASS_E_NOAGGREGATION)

{

cout << "COM class can't be aggregated" << endl;

}

else if (hr == E_NOINTERFACE)

{

cout << "No interface for COM class clsAccount" << endl;

}

else if (hr == E_POINTER)

{

cout << "*ppv pointer was NULL !" << endl;

}

else

{

cout << "Error occurred while creating COM object. HR is [" << hr << "]" << endl;

}

// Free the BSTR because a new one was returned with a call to comutil::ConvertStringToBSTR

SysFreeString(bstrIniFileName);

// Release the string when it's no longer needed. MUST call if string won't be used

// anymore or else a memory leak will occur

env->ReleaseStringUTFChars(iniFileName, nativeIniFileName);

CoUninitialize();

&#12288;

}

catch (_com_error &e)

{

cout << "Encountered an exception in GetCustomerAccountInfo: Error was " << e.ErrorMessage();

pClsAccount->Release();

}

catch (...)

{

pClsAccount->Release();

}

return accountInfoObj;

}

Edited by: Cthulhu76 on Jan 5, 2010 9:18 AM
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Feb 4 2010
Added on Jan 5 2010
7 comments
893 views