• Post Reply Bookmark Topic Watch Topic
  • New Topic

JNI - The data area passed to a system call is too small.

 
Barry Andrews
Ranch Hand
Posts: 529
C++ Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi All,

I am using JNI and Windows native code. In the native code I return the handle to a pointer like this:

return reinterpret_cast<jint> pObj; // pObj is a pointer.

In another JNI method, I pass the integer to the C++ code and re cast it back to the pointer and use it.

This works most of the time, but sometimes the JVM crashes. So I found the code where the crash occurs and wrapped it in a try-catch block. Then I found the error with the GetLastError() method. The error code that is returned is "The data area passed to a system call is too small." I am not sure what this error really means. Microsoft is not much help. My theory is that somehow either the pointer is getting corrupted or the data it points to is. But why would this work in some cases and not others? If I just use the straight C++ code without going through JNI, then it works 100% of the time. So here has to be something going wrong with the JNI access. Does anyone have a clue? Has anyone had a similar issue?

many many thanks,

Barry
 
Jayesh Lalwani
Ranch Hand
Posts: 502
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That exception is similar to ArrayOutOfBoundsException in java, except that it's not guaranteed to be always thrown. There are a lot of APIs that can throw that exception, and you cannot tell what the problem is by just looking at the error message. You will have to consider the source of the exception.

Can you figure out which line of code is generating the exception? Could be because there is a bug in the line of code. Can you post your source code and point to the line tht generates the exception?

It is possible that this exception is being caused by memory corruptions, and you will have to review your entire C++ code to weed out memory corruptions. However, before you go down that hole, I would first start by looking at the code that generated that exception. Maybe it's a simple buffer overrun, and fixing memory allocation might fix the problem
 
Barry Andrews
Ranch Hand
Posts: 529
C++ Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I know the call that fails on the C++ side. I just make 1 call to some legacy C++ code which has been around for years and still works today. To this legacy method I pass the 2 pointers which were receieved from the Java side. So I come to the conclusion that the pointers are invalid. The question is why?

Interestingly, someone in the Java Forums - Native Methods said he uses long instead of int to handle passing pointers around in JNI. So I gave that a try and sure enough it did help. It works MUCH better now, but there still is some issue because it does not work 100% of the time.
 
Jayesh Lalwani
Ranch Hand
Posts: 502
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Barry Andrews:
I know the call that fails on the C++ side. I just make 1 call to some legacy C++ code which has been around for years and still works today.


Ok, let me get this correct. So, the line which generates this exception calls a legacy C++ function that you do not have the code for?

Can you trace the problem down to the actual call to Windows API?


To this legacy method I pass the 2 pointers which were receieved from the Java side. So I come to the conclusion that the pointers are invalid. The question is why?

Not neccesarily. Let me try to give an overview of how this error code is usually used. In Windows , many of the APIs provided by windows look like this

void GetXXX(byte* lpBuffer, DWORD sizeOfBuffer, DWORD* requiredSize);

Before you make the call to this function, you are suppossed to allocate the correct number of bytes to lpBuffer, and provide the size of the buffer in sizeOfBuffer. So, a rudimentary way of calling this function would be



The first thing the API will do is compare the sizeOfBuffer parameter with the actual size of XXX. If the size is too less, then it will throw ERROR_INSUFFICIENT_BUFFER(which is what you are getting). If sizeOfBuffer is enough, it will fill the buffer with contents of XXX

So, whenever you get this error, there could be 2 things happenning
a) the memory allocated to your pointer is less than the API wants
b) pointers and other data on the heap is corrupted

You need to rule out a) before you can investigate b). It could happen that this error occurs ony under certain conditions, and the reason you are not seeing it 100% of the time is because you don't recreate the same conditions 100% of the time.

It also depends on the data you are trying to get. For example, one popular Windows API that is used to list the printers on the network uss the above technique. Now, in many big intranet systems, the number of printers on the network are not constant. People turn their printers on and off all the time, and at any given time the number of printers change. So, at one meoment the network would have 100 printers, and you will allocate memory for 100 printers, but in the meantime another printer turns on, and now you will get the ERROR_INSUFFICIENT_BUFFER error

I know this is an odd way of doing things

Investigating memory corruption


Interestingly, someone in the Java Forums - Native Methods said he uses long instead of int to handle passing pointers around in JNI. So I gave that a try and sure enough it did help. It works MUCH better now, but there still is some issue because it does not work 100% of the time.


Is that long or jlong? long is not the same as jlong. In Windows, jlong is _int64 and long is the same as jint. In Java int is 4 bytes. A C++ pointer is also 4 bytes. I don't have a problem with typecasting a C++ pointer to a jint rather than a jlong, unless there is some justification

I do have problems with typecasting C++ pointer to anything else other than a C++ pointer. Generally, I avoid passing C++ pointers back and forth between Java and C++, precisely because of the problems that you are facing. When you are typecasting a pointer to any other integral type, you might run into problems that occur because of type-unsafe operations. Being able to fundamentally type cast on type to another is one of the biggest flaws of C++ and should be avoided. However, I don't want to go into the details of this because changing this might affect your application drastically.
 
Barry Andrews
Ranch Hand
Posts: 529
C++ Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for your information! I did find my problem. I was overwriting those pointers myself on the C++ side. You are right, passing pointers between Java and C++ can be a pain, but in this case I have to do it. Thanks again!
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!