aspose file tools*
The moose likes Other JSE/JEE APIs and the fly likes Problem with ReleaseStringUTFChars (Crash ) Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Soft Skills this week in the Jobs Discussion forum!
JavaRanch » Java Forums » Java » Other JSE/JEE APIs
Bookmark "Problem with ReleaseStringUTFChars (Crash )" Watch "Problem with ReleaseStringUTFChars (Crash )" New topic
Author

Problem with ReleaseStringUTFChars (Crash )

Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
Hi I am using the below stated code in JNI:

It fails if any of the values in pParams is large... And it doesn't crashes always but in most of the cases when the large value is passed.


**************

for (int i = 0; i < paramCount; i++) {s
jobjectArray param = (jobjectArray)pEnv->GetObjectArrayElement(pParams, i);
jstring str1 = (jstring)pEnv->GetObjectArrayElement(param, 0);
jstring str2 = (jstring)pEnv->GetObjectArrayElement(param, 1);
const char *name = pEnv->GetStringUTFChars(str1, 0);
const char *value = pEnv->GetStringUTFChars(str2, 0);

cout <<name <<"=" <<value <<endl;

returnVal = PSMsgSetField(hContext, name, value);

if (returnVal != PSMSG_OK) {
cout << "Error in SetField: " << returnVal << endl;
}

pEnv->ReleaseStringUTFChars(str1, name);

pEnv->ReleaseStringUTFChars(str2, value);
}

returnVal = PSMsgProcessMessage(hContext, &replyOption);
pEnv->ReleaseStringUTFChars(pTopic, topic);

pEnv->ReleaseStringUTFChars(pMsgName, msgName);

pEnv->ReleaseStringUTFChars(pActivity, activity);

***************
[ May 14, 2006: Message edited by: Andy Smith ]

Share Knowledge to gain it.
SCJP 2, SCWCD 2, SCDJWS, IBM 141 (In Progress), IBM 486 (Next)
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

You're not checking for NULL or for exceptions after calling GetStringUTFChars; it can throw OutOfMemoryError and return NULL. Probably that's what's happening.
[ May 12, 2006: Message edited by: Ernest Friedman-Hill ]

[Jess in Action][AskingGoodQuestions]
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
Thank For ur reply.

I noticed one thing..

"param" is not released using "ReleaseStringUTFChars" in the loop...

Could that be the reason ?

Should I add something like "pEnv->ReleaseStringUTFChars(param, pParams);"

I am not much aware of the JNI ...
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

Originally posted by Andy Smith:
T
Could that be the reason ?


No.

Please check the return value of getStringUTFChars for NULL -- I'm telling you, that's the problem. Then later, you're trying to release NULL and it's crashing.
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
Hi I got ur point...

U want to say that some exception is occuring (OutOfMemmory) and thats y the variable is null

OK by adding null check, I would be able to avoid this prob..But still the main problem is why the exception OutOfmemry to wat ever...

This fail 90 % of times...
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

You're getting OutOfMemoryErrors because you're running out of memory. This really doesn't seem to me to be so difficult to understand. Remember that you can increase the size of the Java heap with command-line switches, and that may be necessary here.
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
I am sorry for askin u a bad question.. but I really have never worked on C++.. and I need to send this file to some one to compile ang give me back so I just want to be sure of How to add the Null Check u r talking abt...


Could you please help talking the example of codeI ahve posted in my earlier message
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

If a JNI routine wants to throw an exception, it can't really throw it in C, of course, since C has no exceptions. It just stores the exception object in a special place where you can check for it. Many JNI routines will also return a special value (often NULL, or 0) to indicate that there was an exception. If you see a NULL return, you know there was an exception; you should clean up as best you can, freeing memory as needed, and then return; Java will see that stored exception and throw it.

So, for example, you can just do something like



This kind of error checking adds a lot of code, but unfortunately it's necessary.
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
Thank You Sir...

I will change my code to this :

*****************************************
for (int i = 0; i < paramCount; i++) {
jobjectArray param = (jobjectArray)pEnv->GetObjectArrayElement(pParams, i);
jstring str1 = (jstring)pEnv->GetObjectArrayElement(param, 0);
jstring str2 = (jstring)pEnv->GetObjectArrayElement(param, 1);
const char *name = pEnv->GetStringUTFChars(str1, 0);
const char *value = pEnv->GetStringUTFChars(str2, 0);

cout <<name <<"=" <<value <<endl;

returnVal = PSMsgSetField(hContext, name, value);

if (returnVal != PSMSG_OK) {
cout << "Error in SetField: " << returnVal << endl;
}

if (name == 0){
pEnv->ReleaseStringUTFChars(str1, name);
)

if (name == 0){
pEnv->ReleaseStringUTFChars(str2, value);
}
}

returnVal = PSMsgProcessMessage(hContext, &replyOption);

if (topic == 0) {
pEnv->ReleaseStringUTFChars(pTopic, topic);
}

if (msgName == 0) {
pEnv->ReleaseStringUTFChars(pMsgName, msgName);
}

if (activity == 0 ) {
pEnv->ReleaseStringUTFChars(pActivity, activity);
}

*********************************************

This should be ok now ?

One more thing, I have also used
***************************************
returnVal = PSMsgSetField(hContext, name, value);
**************************************

Do I need some sort of checking here also ?
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

My goodness, no; I'm sorry, but this is all wrong!

The idea is that if a method fails, then you need to release all resources that you successfully allocated before the failure, and then return. And of course, you need to check for successful allocation before you use a resource. In the code you've shown, you allocate "name" and "value", then use them without checking if they're OK. Then you check if they're OK, and free them only if they're not; this is really all in all the exact opposite of what you need to do! Instead, you want to do what I showed in my example, all of it before calling PSMsgSetField. If name or value is 0, then you should not call PSMsgSetField, but instead clean up and return.

Note in my example that if we fail to allocate "name", then we just return. And if we fail to allocate "value", then we need to free "name", since if we got here then we successfully allocated "name" previously -- and then after cleaning up "name", we return.

If, on the other hand, "value" is nonzero, then everything is OK, and we can call PSMsgSetField. Then, continuing on, we need to check every other call to GetStringUTFChars for a zero return, and clean up any strings that we previously allocated, and abort the routine.

Remember never pass to a zero char* to ReleaseStringUTFChars!
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
I really appreciate your really fast responses...

Ok let me try again, I hope it should be ok now

*****************************************
for (int i = 0; i < paramCount; i++) {
jobjectArray param = (jobjectArray)pEnv->GetObjectArrayElement(pParams, i);
jstring str1 = (jstring)pEnv->GetObjectArrayElement(param, 0);
jstring str2 = (jstring)pEnv->GetObjectArrayElement(param, 1);
const char *name = pEnv->GetStringUTFChars(str1, 0);
const char *value = pEnv->GetStringUTFChars(str2, 0);

cout <<name <<"=" <<value <<endl;

if ((name != 0) && (value != 0)) {
returnVal = PSMsgSetField(hContext, name, value);
}

if (returnVal != PSMSG_OK) {
cout << "Error in SetField: " << returnVal << endl;
}

if (name != 0) {
pEnv->ReleaseStringUTFChars(str1, name);
)

if (value != 0) {
pEnv->ReleaseStringUTFChars(str2, value);
}
}

returnVal = PSMsgProcessMessage(hContext, &replyOption);

if (topic != 0) {
pEnv->ReleaseStringUTFChars(pTopic, topic);
}

if (msgName != 0) {
pEnv->ReleaseStringUTFChars(pMsgName, msgName);
}

if (activity != 0 ) {
pEnv->ReleaseStringUTFChars(pActivity, activity);
}

*****************************************


Please provide your commnets
[ May 14, 2006: Message edited by: Andy Smith ]
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

This is much closer, but you're still cutting corners. Whenever you make a single, individual JNI call that might fail by throwing an exception -- and the JNI documentation lists the exceptions that each method might throw -- you must check for an exception and deal with immediately. You have two choices: you can clean up and then return, or you can call env->ClearException() and continue. The JNI spec says that the result of calling many JNI routines while there is a pending exception is undefined; in practice, this often means that if you do it, you'll get a crash. So if you're going to continue, you must clear the exception.

I see now that all this code is in a loop, so you probably don't want to just return if there's a problem, but rather go ahead to the next iteration of the loop; you might use the "continue" statement, which is just like Java's; clean up and continue.
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
Thanx Again

How abt this ?

****************************************************************************
// set all input fields
for (int i = 0; i < paramCount; i++) {
jobjectArray param = (jobjectArray)pEnv->GetObjectArrayElement(pParams, i);
jstring str1 = (jstring)pEnv->GetObjectArrayElement(param, 0);
jstring str2 = (jstring)pEnv->GetObjectArrayElement(param, 1);
const char *name = pEnv->GetStringUTFChars(str1, 0);
jth = pEnv->ExceptionOccurred ();
if (jth) {
printf ("There was an exception Getting Name \n");
pEnv->ExceptionDescribe ();
pEnv->ExceptionClear ();
}

const char *value = pEnv->GetStringUTFChars(str2, 0);
jth = pEnv->ExceptionOccurred ();
if (jth) {
printf ("There was an exception Getting Value \n");
pEnv->ExceptionDescribe ();
pEnv->ExceptionClear ();
}

cout <<name <<"=" <<value <<endl;
cout << "Before PSMsgSetField..." << endl;

returnVal = PSMsgSetField(hContext, name, value);
if (returnVal != PSMSG_OK) {
cout << "Error in SetField: " << returnVal << endl;
}

// Name
cout << "Releasing Name..." << endl;
if (name != 0) {
cout << "Name..." << endl;
pEnv->ReleaseStringUTFChars(str1, name);
}

jth = pEnv->ExceptionOccurred ();
if (jth) {
printf ("Exception Releasing Name \n");
pEnv->ExceptionDescribe ();
pEnv->ExceptionClear ();
}

// Value
cout << "Releasing Value..." << endl;
if (value != 0) {
cout << "Value..." << endl;
pEnv->ReleaseStringUTFChars(str2, value);
}

jth = pEnv->ExceptionOccurred ();
if (jth) {
printf ("Exception Releasing Value \n");
pEnv->ExceptionDescribe ();
pEnv->ExceptionClear ();
}
}

returnVal = PSMsgProcessMessage(hContext, &replyOption);

// Topic
cout << "Releasing Topic..." << endl;
if (topic != 0) {
cout << "Topic..." << endl;
pEnv->ReleaseStringUTFChars(pTopic, topic);
}

jth = pEnv->ExceptionOccurred ();
if (jth) {
printf ("Exception Releasing Topic \n");
pEnv->ExceptionDescribe ();
pEnv->ExceptionClear ();
}

// msgName
cout << "Releasing msgName" << endl;
if (msgName != 0) {
cout << "msgName..." << endl;
pEnv->ReleaseStringUTFChars(pMsgName, msgName);
}

jth = pEnv->ExceptionOccurred ();
if (jth) {
printf ("Exception Releasing msgName \n");
pEnv->ExceptionDescribe ();
pEnv->ExceptionClear ();
}

// activity
cout << "Releasing activity" << endl;
if (activity != 0) {
cout << "activity..." << endl;
pEnv->ReleaseStringUTFChars(pActivity, activity);
}
jth = pEnv->ExceptionOccurred ();
if (jth) {
printf ("Exception Releasing Activity \n");
pEnv->ExceptionDescribe ();
pEnv->ExceptionClear ();
}

****************************************************************************
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
Hi

I have executed the application with the changes, still facing the same problem..

It is while releasing the "Value" and the size of the value is more then 320 characters....


any idea ??
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
I have added this:-

// Value
cout << "Releasing Value..." << endl;
if ((str2!= NULL) && (str2 != 0) && (value != NULL) && (value != 0)) {
cout << "Value..." << endl;
pEnv->ReleaseStringUTFChars(str2, value);
}


It is going inside the loop, and fails i "Release..." when the length of the value is more then 350 Chars
[ May 15, 2006: Message edited by: Andy Smith ]
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

Fails in what way, and how do you know where in the code it is when it fails?
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
I have put some "Cout" statements, thats how I come to know where it fails...

I am using this in the form of dll.. I get a popup saying "Abnormal Program Termination" with the heading "VC++ Runtime Libratry Error"
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

Hmm. Well, what does PSMsgSetField do with "value"? Is the problem perhaps caused by the char* being freed without PSMsgSetField expecting it? Is PSMsgSetField expecting a shorter char*?
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
This is the signature of te method

MSGAPIFUNCTION PSMsgSetField(PSMSGHANDLE hContext,
LPCSTR lpcszFieldName,
LPCSTR lpcszValue);


Strange thing is that it works for the first time. Then Crashes the next time, and always works for the smaller size of the value.

It ONLY Runs for one time when the message length is > 320, May be this can give some idea
[ May 15, 2006: Message edited by: Andy Smith ]
Andy Smith
Ranch Hand

Joined: Sep 28, 2003
Posts: 239
I m using:-

const char *value = pEnv->GetStringUTFChars(str2, 0);

Should I try passing a jboolean as second parameter something like:

jboolean isCopy;
*value = (pEnv)->GetStringUTFChars(theString,&isCopy);

and releasing on the basis of isCopy...

What do u think ?


**************

jstring utf_str =
(jstring) env->GetObjectArrayElement(objArray, i);
const char* c = env->GetStringUTFChars(utf_str, &isCopy);
fprintf(stdout, "\t objArray[%d] = (%s)\n", i, c);
if (isCopy == JNI_TRUE) {
env->ReleaseStringUTFChars(utf_str, c);
}
env->DeleteLocalRef(utf_str);
*****************
Should I change code to look like this ?
1. Using isCopy .

2. Using DeleteLocalRef.


?
[ May 15, 2006: Message edited by: Andy Smith ]
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Problem with ReleaseStringUTFChars (Crash )