Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

JNI Problems, GetByteArrayElements / ReleaseByteArrayElements

974 views
Skip to first unread message

Tom Hampton

unread,
Jul 28, 2003, 4:55:01 PM7/28/03
to
GetByteArrayElements/ReleaseByteArrayElements are failing releasing the
InputDataBuffer in the code below. It works several
times before failing on an input buffer of 1 byte. Anyone have any idea why
it's failing ? Is it a bug in the JVM ?

JNIEXPORT jint JNICALL Java_com_igen_otishelper_JOTISHelper_JniExecute
(JNIEnv *jEnv, jobject jObj, jint deviceDriverHandle,
jint commandType, jint commandID, jshort taskID, jbyteArray jInArray,
jint inSize, jbyteArray jOutArray, jint outSize) {

OTIS_STATUS otisStatus;
UINT16 bytesReceived = 0;

jboolean inCopy = JNI_FALSE;
jbyte * inputDataBuffer = inSize > 0 ?
jEnv->GetByteArrayElements(jInArray, &inCopy) : NULL;

jboolean outCopy = JNI_FALSE;
jbyte * outputDataBuffer = outSize > 0 ?
jEnv->GetByteArrayElements(jOutArray, &outCopy) : NULL;

memset(outputDataBuffer, 0, outSize);

int ioSuccessful = OtisDevIo(deviceDriverHandle,
commandID | ((static_cast<OtisInterface_t>(taskID)) << 8),
(void *)inputDataBuffer,
inSize,
(void *)outputDataBuffer,
outSize,
&otisStatus,
&bytesReceived);

if (outputDataBuffer && outCopy == JNI_TRUE) {
jEnv->ReleaseByteArrayElements(jOutArray, outputDataBuffer, 0);
}

if (inputDataBuffer && inCopy == JNI_TRUE) {
jEnv->ReleaseByteArrayElements(jInArray, inputDataBuffer, 0); //
!!! - Fails on this Release call
}

if (ioSuccessful != 0) {
throwJNIException(jEnv, "Failure to send command to driver.",
ERR_OTIS_SEND_FAILURE);
return 0; // no status to report
} else if (bytesReceived != outSize) {
throwJNIException(jEnv, "Unexpected number of bytes recieved.
Recieved ", ERR_OTIS_SEND_FAILURE);
return 0; // no status to report
}

return otisStatus & 0xFF;
}


Simon Archer

unread,
Jul 28, 2003, 7:22:55 PM7/28/03
to
Tom

What do you mean by "failing to release the InputDataBuffer". Unfortuately
you say nothing about the platform you're running on, version of the j9 VM,
and perhaps some example output of the problem would be helpful. Another
suggestion worth considering is building an example that has no dependencies
on any other code; in other words, get rid of the OtisDevIo(...) call and
anything that would prevent someone on this newgroup from trying to
reproduce the problem.

Having briefly read your JNI code I can tell you that you need to review the
meaning of the isCopy parameter. In a nutshell, an allocated byte array
should always be released using ReleaseByteArrayElements(...) regardless of
whether isCopy is true or false. The value of isCopy simply tells you
whether changes you make to the "copy" of the byte array will be visible to
the "copy" in the JVM. The JVM is at liberty to copy the Java byte array or
simply pass back a jbyte pointer to the memory.

Granted, the definition of GetByteArrayElements(...) has been incorrectly
documented in publications, but I would strongly advice you review the
following softcopy of the JNI book http://java.sun.com/docs/books/jni/.
Here's an except from section 3.2.4 that discusses ReleaseStringChars(...),
which has similar semantics to ReleaseByteArrayElements(...):

"Do not forget to call ReleaseStringChars when you no longer need access to
the string elements returned from GetStringChars. The ReleaseStringChars
call is necessary whether GetStringChars has set *isCopy to JNI_TRUE or
JNI_FALSE. ReleaseStringChars either frees the copy or unpins the instance,
depending upon whether GetStringChars has returned a copy or not. "

I hope this helps,

Simon

"Tom Hampton" <hamp...@igen.com> wrote in message
news:bg42j5$8b7o$1...@news.boulder.ibm.com...

Tom Hampton

unread,
Jul 29, 2003, 10:28:58 AM7/29/03
to
Thanks, for your help.

I using QNX on x86 and WCE 5.0 - Max configuration. Updated code & output
are below.

I called the ReleaseByteArrayElements reguardless of the copy variable as
you suggested. Thanks
for clearing that up for me. I wasn't clear how that was supposed to work.
It's interesting that if I
put an extra GetByteArrayElements(jInArray, 0) call at the beginning that
this function works (see
the comment in the code). The OtisDevIo function sends a message to
hardware and fills in the
outputDataBuffer. It doesn't alter the inputDataBuffer at all. It could
just be commented out to run
this function.

JNIEXPORT jint JNICALL Java_com_igen_otishelper_JOTISHelper_JniExecute
(JNIEnv *jEnv, jobject jObj, jint deviceDriverHandle,
jint commandType, jint commandID, jshort taskID, jbyteArray jInArray,
jint inSize, jbyteArray jOutArray, jint outSize) {

OTIS_STATUS otisStatus;
UINT16 bytesReceived = 0;

/* !!!!! - if this code is uncommented this function works fine.
* but this code should not be here.
if (jInArray) {
jbyte *x = jEnv->GetByteArrayElements(jInArray, 0);
}
*/

jboolean inCopy = JNI_FALSE;
jbyte * inputDataBuffer = inSize > 0 ?
jEnv->GetByteArrayElements(jInArray, &inCopy) : NULL;

jboolean outCopy = JNI_FALSE;
jbyte * outputDataBuffer = outSize > 0 ?
jEnv->GetByteArrayElements(jOutArray, &outCopy) : NULL;

memset(outputDataBuffer, NULL, outSize);

int ioSuccessful = OtisDevIo(deviceDriverHandle,
commandID | ((static_cast<OtisInterface_t>(taskID)) << 8),
(void *)inputDataBuffer,
inSize,
(void *)outputDataBuffer,
outSize,
&otisStatus,
&bytesReceived);

if (outputDataBuffer) {
jEnv->ReleaseByteArrayElements(jOutArray, outputDataBuffer, 0);
}

if (inputDataBuffer) {
cout << "start release inputDataBuffer" << endl;
jEnv->ReleaseByteArrayElements(jInArray, inputDataBuffer, 0);
cout << "finish release inputDataBuffer" << endl;
}

if (ioSuccessful != 0) {
throwJNIException(jEnv, "Failure to send command to driver.",
ERR_OTIS_SEND_FAILURE);
return 0; // no status to report
} else if (bytesReceived != outSize) {
throwJNIException(jEnv, "Unexpected number of bytes recieved.
Recieved ", ERR_OTIS_SEND_FAILURE);
return 0; // no status to report
}

return otisStatus;
}

Here's the error that I get. It fails on the
jEnv->ReleaseByteArrayElements(jInArray, inputDataBuffer, 0); call.
I know this because I put debug print statements around that line of code.
Notice that the "start release inputDataBuffer"
was printed just before the thread dump.


start release inputDataBuffer
finish release inputDataBuffer
start release inputDataBuffer
finish release inputDataBuffer
start release inputDataBuffer
finish release inputDataBuffer
start release inputDataBuffer
finish release inputDataBuffer
start release inputDataBuffer
Unhandled exception
Type=GPF vmState=0xffffffff
Handler1=0xb8248414 Handler2=0xb82344f8
Signal=0x0000000b
EFlags=0x00011286
EDI=0x08056b88 ESI=0x08056b8c EAX=0x08056be4
EBX=0xb034ffe4 ECX=0x100ad770 EDX=0x08d4012c
EBP=0x08046a50 ESP=0x08046a28 EIP=0xb031c5de
CS=0x0000001f SS=0x00000027

Thread: main (priority 5) (LOCATION OF ERROR)
NATV
com/igen/lifesci/appsrv/inst/physdev/otishelper/JOTISHelper.JniExecute(IIIS[
BI[BI)I
0010
com/igen/lifesci/appsrv/inst/physdev/otishelper/JOTISHelper.sendOTISCommand(
IIS[BI[BI)I
001d
com/igen/lifesci/appsrv/inst/physdev/otishelper/JOTISHelper.getFirmwareInfo(
[Ljava/lang/String;B)I
0003
com/igen/lifesci/appsrv/inst/physdev/otishelper/JOTISHelper.getSerialNumber(
[Ljava/lang/String;)I
000f
com/igen/lifesci/appsrv/inst/physdev/combinedboard/MotionController.doGetSer
ialNumber()Ljava/lang/String;
0125
com/igen/lifesci/appsrv/inst/physdev/combinedboard/MotionController$CBOpenOp
.execute()Ljava/lang/Object;
0004
com/igen/lifesci/appsrv/inst/physdev/PhysicalDevice$OpenOp.execute()Ljava/la
ng/Object;
000e
com/igen/lifesci/appsrv/inst/physdev/PhysicalDevice$StatusUpdatingOp.execute
()Ljava/lang/Object;
00d9
com/igen/lifesci/appsrv/inst/physdev/PhysicalDevice$StatusCheckingOp.execute
()Ljava/lang/Object;
0029
com/igen/lifesci/appsrv/inst/deviceop/LockingDeviceOp.execute()Ljava/lang/Ob
ject;
004d
com/igen/lifesci/appsrv/inst/physdev/combinedboard/MotionController.Open()V
0033 com/igen/lifesci/appsrv/inst/Instrument.connectPhysicalDevices()V
0001
com/igen/lifesci/appsrv/inst/Instrument.access$1(Lcom/igen/lifesci/appsrv/in
st/Instrument;)V
0078
com/igen/lifesci/appsrv/inst/Instrument$ConnectOp.execute()Ljava/lang/Object
;
000e
com/igen/lifesci/appsrv/inst/Instrument$ExecutionStatusUpdatingOp.execute()L
java/lang/Object;
00d6
com/igen/lifesci/appsrv/inst/Instrument$StatusCheckingOp.execute()Ljava/lang
/Object;
0006
com/igen/lifesci/appsrv/inst/deviceop/EventHandlingDeviceOp.execute()Ljava/l
ang/Object;
0040
com/igen/lifesci/appsrv/inst/Instrument.connect(Ljava/lang/String;Ljava/lang
/String;Ljava/lang/String;)V
00f8
com/igen/lifesci/appsrv/inst/instmgr/InstrumentManager.GetInstrument(Ljava/l
ang/String;)Ljava/lang/Object;
004e unit/appsrv/inst/ConsoleInstTest.main([Ljava/lang/String;)V

Thread: Gc Thread (priority 5) (daemon)

Thread: Finalizer thread (priority 5) (daemon)

Thread: EventLogger Timer Thread (priority 5) (daemon)
NATV java/lang/Object.wait(JI)V
0003 java/lang/Object.wait(J)V
0015 com/igen/lifesci/appsrv/eventlogger/EventLogger$TimerThread.run()V
000b java/lang/Thread.run()V


"Simon Archer" <sar...@nc.rr.com> wrote in message
news:bg4avo$9fdo$1...@news.boulder.ibm.com...

Patrick Mueller

unread,
Jul 29, 2003, 10:55:34 AM7/29/03
to

You might want to make sure stdout (cout) is getting flushed. It's not
uncommon to have unflushed data in the buffer somewhere that you end up not
seeing.

From looking at your code, you are assuming that the byte arrays are at
least the size specified in the 'size' parameters. You might want to double
check this to make sure they are actually big enough by calling
GetArrayLength().

We also have a way of doing some checking on your behalf for some JNI stuff.
Try using the option -Xrunjnichk:verbose to see if it complains about
anything.

--
Patrick Mueller
pmu...@yahoo.com


Tom Hampton

unread,
Jul 29, 2003, 11:10:00 AM7/29/03
to
The buffers are of the correct size. I did have debug output printing the
size of the buffers, but
when I saw that they were correct I removed them. Good suggestion though to
double check.

The cout cmd should is flushed. The "endl" flushes the stream.

Here's the output using the -Xrunjnichk:verbose option. I'm not sure, but
dosn't look like
it's complaining about anything.

<JNI check utility installed>
<JNI FindClass: java/lang/ClassLoader>
<JNI FindClass: java/lang/String>
<JNI GetMethodID: java/lang/String.<init> ([BII)V>
<JNI GetFieldID: java/io/FileInputStream.fd Ljava/io/FileDescriptor;>
<JNI GetFieldID: java/io/FileDescriptor.descriptor I>
<JNI GetFieldID: java/io/FileOutputStream.fd Ljava/io/FileDescriptor;>
<JNI FindClass: [B>
<JNI FindClass: java/security/AccessController>
<JNI GetStaticMethodID: java/security/AccessController.doPrivileged
(Ljava/security/PrivilegedAction;)Ljava/lang/Object;>
<JNI GetStaticMethodID: java/security/AccessController.doPrivileged
(Ljava/security/PrivilegedExceptionAction;)Ljava/lang/Object;>
<JNI GetStaticMethodID: java/security/AccessController.doPrivileged
(Ljava/security/PrivilegedAction;Ljava/security/AccessControlContext;)Ljava/
lang/Object;>
<JNI GetStaticMethodID: java/security/AccessController.doPrivileged
(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContex
t;)Ljava/lang/Object;>
<JNI GetStaticFieldID: java/lang/ClassLoader.applicationClassLoader
Ljava/lang/ClassLoader;>
<JNI GetFieldID: java/lang/ClassLoader.vmRef I>
<JNI FindClass: java/lang/ThreadGroup>
<JNI GetStaticFieldID: java/lang/ThreadGroup.systemThreadGroup
Ljava/lang/ThreadGroup;>
<JNI FindClass: java/lang/String>
<JNI GetMethodID: java/lang/String.<init> ([BII)V>
<JNI FindClass: unit/appsrv/inst/ConsoleInstTest>
<JNI FindClass: java/util/zip/ZipEntry>
<JNI GetMethodID: java/util/zip/ZipEntry.<init>
(Ljava/lang/String;Ljava/lang/String;[BJJJJIJJ)V>
<JNI GetFieldID: java/util/zip/ZipFile.descriptor J>
<JNI FindClass: java/util/zip/ZipFile$ZFEnum>
<JNI GetFieldID: java/util/zip/ZipFile$ZFEnum.nextEntryPointer J>
<JNI FindClass: java/io/IOException>
<JNI GetMethodID: java/io/IOException.<init> (Ljava/lang/String;)V>
<JNI FindClass: java/lang/Boolean>
<JNI GetMethodID: java/lang/Boolean.<init> (Z)V>
<JNI GetFieldID: java/lang/Boolean.value Z>
<JNI FindClass: java/lang/Byte>
<JNI GetMethodID: java/lang/Byte.<init> (B)V>
<JNI GetFieldID: java/lang/Byte.value B>
<JNI FindClass: java/lang/Integer>
<JNI GetMethodID: java/lang/Integer.<init> (I)V>
<JNI GetFieldID: java/lang/Integer.value I>
<JNI FindClass: java/net/InetAddress>
<JNI GetMethodID: java/net/InetAddress.<init> (I)V>
<JNI GetMethodID: java/net/InetAddress.<init> (ILjava/lang/String;)V>
<JNI GetFieldID: java/net/InetAddress.address I>
<JNI FindClass: java/lang/Thread>
<JNI GetStaticMethodID: java/lang/Thread.yield ()V>
<JNI GetStaticMethodID: unit/appsrv/inst/ConsoleInstTest.main
([Ljava/lang/String;)V>

Initialize instrument (Tue Jul 29 10:01:49 GMT 2003)...
<JNI FindClass: java/lang/Object>
<JNI GetMethodID: java/lang/Object.finalize ()V>
<JNI FindClass: java/lang/ref/Reference>
<JNI GetMethodID: java/lang/ref/Reference.enqueueImpl ()Z>


Unhandled exception
Type=GPF vmState=0xffffffff
Handler1=0xb8248414 Handler2=0xb82344f8
Signal=0x0000000b
EFlags=0x00011286
EDI=0x08056b88 ESI=0x08056b8c EAX=0x08056be4

EBX=0xb034ffe4 ECX=0x100ad770 EDX=0x08d70024
EBP=0x080469a8 ESP=0x08046980 EIP=0xb031c5de
CS=0x0000001f SS=0x00000027


>

Patrick Mueller

unread,
Jul 29, 2003, 1:34:23 PM7/29/03
to
Tom Hampton wrote:
> The buffers are of the correct size. I did have debug output
> printing the size of the buffers, but
> when I saw that they were correct I removed them. Good suggestion
> though to double check.

Definitely add the check. You (or someone else) may change the java code
someday and ... whoops!

> The cout cmd should is flushed. The "endl" flushes the stream.

of course! c++ is so obvious :-) Actually, I guessed it was, otherwise
you're output would have been a bit funkier.

> Here's the output using the -Xrunjnichk:verbose option. I'm not
> sure, but dosn't look like
> it's complaining about anything.

> ...

Looks ok.

Try the VM option -memorycheck also. This does the usual boundary condition
checks around memory the VM allocates to let you know if anyone stepped on
it. If your C code is overwriting the buffer, for instance, you may get
notified of this. Or, with a crash like this, the damage could have easily
be done somewhere else, and just surfacing here. -memorycheck won't find
your problem, but it will let you know if you have a problem.

--
Patrick Mueller
pmu...@yahoo.com


Patrick Mueller

unread,
Jul 29, 2003, 1:43:26 PM7/29/03
to
I also tend to increase the native stack size when stuff like this happens.
Perhaps your C functions are stack-hungry.

Use -Xmso to increase the stack. To see the current values, run:
"j9 -verbose:sizes X" (use X for a bogus class name, you won't get the
output without it).

--
Patrick Mueller
pmu...@yahoo.com


Tom Hampton

unread,
Jul 31, 2003, 10:45:04 AM7/31/03
to
Very interesting results with the -memorycheck option. Seems to be failing
in the ReleaseByteArrayElements call.
Below the memory output is the code for the OtisDevIo function. It is just
a simple wrapper around the QNX devctl()
function. I'm pretty sure there are no memory handling flaws in the
OtisDevIo function, so I believe the JVM is corrupting
memory some how. Also, this is the only JNI code in the system.

ERROR: Tried free_memory on 8e52068 (header at 8e51e68), but block is not on
the allocated list
free_memory describing block at 8e52068 (header at 8e51e68):
Block has unrecognized padding 2068dded bef008e5 (header is probably
trashed)!
(only top padding + first 64 bytes of user data will be printed here)
Block header:
08E51E60: - - - - - - - - FF FF FF FF FE 04 00 00 ........
08E51E70: 00 00 00 00 00 00 00 00 ........
Top padding:
08E51E70: - - - - - - - - ED DD 68 20 E5 08 F0 BE ..h ....
08E51E80: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51E90: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51EA0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51EB0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51EC0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51ED0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51EE0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51EF0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F00: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F10: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F20: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F30: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F40: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F50: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F60: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F70: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F80: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51F90: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51FA0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51FB0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51FC0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51FD0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51FE0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E51FF0: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E52000: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E52010: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E52020: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E52030: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E52040: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E52050: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E52060: ED DD 68 20 E5 08 F0 BE ..h ....
First 64 bytes at block contents:
08E52060: - - - - - - - - ED DD 68 20 00 39 00 00 ..h .9..
08E52070: 00 00 00 00 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..........h ....
08E52080: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E52090: ED DD 68 20 E5 08 F0 BE ED DD 68 20 E5 08 F0 BE ..h ......h ....
08E520A0: ED DD 68 20 E5 08 F0 BE ..h ....
Memory checker statistics:
Total blocks allocated = 2448 ( = most recent allocationNumber)
Total blocks freed = 2183
Total bytes allocated = 25022152
Total bytes freed = 9331957
High water blocks allocated = 304
High water bytes allocated = 15711135
Largest block ever allocated = size 8388608, allocation number 42
Failed allocation attempts = 0
Memory error(s) discovered, calling exit(3)

int OtisDevIo( int fileDes, OTIS_REQUEST request, const void* inBuffer,
UINT16 inBufferLen, void* outBuffer, UINT16 outBufferLen,
OTIS_STATUS* otisStatus, UINT16* outDataBytes )
{
int status; // Function status
size_t outSize; // Number of bytes for the output buffer
size_t bufSize; // Size of the input/output buffer
void* buffer; // Input/output buffer

// Set bufSize to the required size of the input buffer
bufSize = offsetof( OtisReq_t, ReqData[ 0 ] );
bufSize += inBuffer ? inBufferLen : 0;

// Set outSize to the required size of the output buffer
outSize = offsetof( OtisRet_t, RetData[ 0 ] );
outSize += outBuffer ? outBufferLen : 0;

// If the output buffer size is larger than bufSize, update bufSize;
if( outSize > bufSize ) {
bufSize = outSize;
}

// Allocate the I/O buffer
if( NULL != ( buffer = malloc( bufSize ) ) ) {
OtisReq_t* rq; // OTIS request type pointer

rq = (OtisReq_t*)buffer; // Set request pointer to buffer

// Store the request code, input data size, and output data size
rq->ReqCode = request;
rq->ReqDataLen = ( NULL != inBuffer ) ? inBufferLen : 0;
rq->RetDataLen = ( NULL != outBuffer ) ? outBufferLen : 0;

// If there is input data associated with the request, copy it
if( 0 != inBufferLen ) {
memcpy( rq->ReqData, inBuffer, inBufferLen );
}

// Sumbit the DCMD_OTIS_SUBMIT_REQUEST
status =
devctl(
fileDes, // OTIS device
DCMD_OTIS_SUBMIT_REQUEST, // devctl code
buffer, // Input/output data buffer
bufSize, // Size of data buffer
NULL // No device information pointer
);

// Ensure devctl succeeded
if( EOK == status ) {
OtisRet_t* rt; // Pointer to OTIS return data type

rt = buffer; // Set return type pointer to buffer

// If OTIS_STATUS code pointer was given, store the status code
if( otisStatus ) {
*otisStatus = rt->StatusCode;
}

// If output data size pointer was given, store output size
if( outDataBytes ) {
*outDataBytes = rt->RetDataLen;
}

// If output data pointer was given, copy the output data
if( outBuffer ) {
// Ensure the output buffer is large enough for the data
if( outBufferLen >= rt->RetDataLen ) {
// Copy the data from I/O buffer to caller's buffer
memcpy( outBuffer, rt->RetData, rt->RetDataLen );
} else {
// Output buffer to small for data
status = EINVAL;
}
}
}

// Free the input/output buffer
free( buffer );
} else {
// Unable to allocate the input/output buffer
status = ENOMEM;
}

return status;
}

"Patrick Mueller" <pmu...@yahoo.com> wrote in message
news:bg6b7e$7vcm$1...@news.boulder.ibm.com...

Patrick Mueller

unread,
Jul 31, 2003, 11:44:40 AM7/31/03
to
Tom Hampton wrote:
> Very interesting results with the -memorycheck option. Seems to be
> failing in the ReleaseByteArrayElements call.

To be more precise, it's being >noticed< in the ReleaseByteArrayElements
call. Don't assume this call actually caused the problem. The damage may
have been done earlier. The -memorycheck option does this:

- every allocate is actually made bigger; we stuff some signature bytes
before and after the payload we actually return to you.
- every allocate and free walks the list of allocated pointers to make sure
they aren't corrupt.

What you've seen is that ReleaseByteArrayElements is doing a free(), and so
you get the list walk, and it notices the trash-edness of some block.

> Below the memory output is the code for the OtisDevIo function. It
> is just a simple wrapper around the QNX devctl()
> function. I'm pretty sure there are no memory handling flaws in the
> OtisDevIo function, so I believe the JVM is corrupting
> memory some how. Also, this is the only JNI code in the system.

It's been a while since I've seen J9 corrupting memory like this (if ever).
Not that I would claim "it couldn't be us!". It just never is :-)

> ERROR: Tried free_memory on 8e52068 (header at 8e51e68), but block is
> not on the allocated list
> free_memory describing block at 8e52068 (header at 8e51e68):
> Block has unrecognized padding 2068dded bef008e5 (header is probably
> trashed)!
> (only top padding + first 64 bytes of user data will be printed here)

> ...

So there are loads of ED DD 68 20 bytes in there. Does that ring a bell
with you? I'm not sure if I'm reading this correctly, but is the actual
data in your pointer space also in our 'padding' area? That would indicate
that YOUR data got put in OUR padding.

I'd put loads of printf's in both your JNI and your OtisDevIo call to see if
you can narrow this down ...

--
Patrick Mueller
pmu...@yahoo.com


Patrick Mueller

unread,
Jul 31, 2003, 3:34:10 PM7/31/03
to
Tom Hampton wrote:
> I found the problem in a different function where I was doing
> ReleaseStringUTFChars incorrectly. Copy/Paste bug.


See! :-)

We continue to enhance the jnichk stuff, so perhaps we will be able to warn
you in the future, for future copy/paste bugs ...

--
Patrick Mueller
pmu...@yahoo.com


Tom Hampton

unread,
Jul 31, 2003, 3:13:54 PM7/31/03
to
I found the problem in a different function where I was doing
ReleaseStringUTFChars incorrectly. Copy/Paste bug.


Thanks you for you help and patience.
-Tom

"Patrick Mueller" <pmu...@yahoo.com> wrote in message

news:bgbdha$39qm$1...@news.boulder.ibm.com...

Peter Burka

unread,
Aug 5, 2003, 4:49:28 PM8/5/03
to
Hi Tom,

I'd like to enhance jnichk to be able to detect more problems like this.

Can you describe what the actual problem with the call to
ReleaseStringUTFChars was?

Thanks for your help,

/peter

--
Peter Burka
OTI Labs, IBM

"Patrick Mueller" <pmu...@yahoo.com> wrote in message

news:bgbqvj$1132$1...@news.boulder.ibm.com...

0 new messages