JNA and JNI - Attempt to reference unallocated memory - java

I am using JNI (and now JNA to see if the issue changes) to connect Java to a C code. This code has two methods that I am trying to use and they should be called from Java code many times, however, when I do the native calls, I got it:
Call method one = I got a response
Call method two = I got a response
Call method one again = Attempt to reference unallocated memory
(Signal SIGSEGV)
Execution stops with this failure.
I tried to call the first and second methods alone (not calling them one after other) and the issue doesn't occur. It just happens when I call one after other, just like they should work. Looks like I am not freeing the memory as I should or JNA/JNI is doing it.
C code (JNI)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "struct1.h"
#include "struct2.h"
#include "struct3.h"
#include "CALLExternMethod1s.h" //Interface External method
#include "CALLExternMethod2s.h" //Interface External method
#include "com_Method1Java.h" //Interface to Java Class
#include "com_Method2Java.h" //Interface to Java Class
void printStruct(void * structPar, int structSize) {
char buffer[structSize + 1];
memcpy(buffer, structPar, structSize);
buffer[structSize] = 0x00;
printf("{'%s'}\n", buffer);
}
JNIEXPORT jstring JNICALL Java_com_Method1Java_method1(JNIEnv *env, jobject obj, jstring input){
jboolean isCopy;
const char *request = (*env)->GetStringUTFChars(env, input, &isCopy);
struct1 struct1rec;
struct2 struct2rec;
char* response;
int reqLen = strlen(request);
reqLen = (reqLen <= sizeof(struct1)) ? reqLen : sizeof(struct1);
memcpy(&struct1rec, request, reqLen );
printf(" \n------ Struct1 Request ------\n ");
printStruct(&struct1rec, sizeof(struct1));
cob_init(0,NULL);
CALLExternMethod1(&struct1rec,&struct2rec); //Method overrides struct2rec with the response
response = malloc(sizeof(struct2) + 1);
memset(response, 0x20, sizeof(struct2) );
memcpy(response, &struct2rec, sizeof(struct2));
response[sizeof(struct2)] = '\0';
printf(" \n------ Struct2 Response ------\n ");
printStruct(response, sizeof(struct2));
(*env)->ReleaseStringUTFChars(env, input, request);
jstring result = (*env)->NewStringUTF(env, response);
free(response);
(*env)->PopLocalFrame(env,NULL);
printf("--- end of method1 JNI ---\n");
return result;
}
JNIEXPORT jstring JNICALL Java_com_Method2Java__struct3(JNIEnv *env, jobject obj, jstring input){
jboolean isCopy;
const char *request = (*env)->GetStringUTFChars(env, input, &isCopy);
struct3 struct3rec;
char* response;
int reqLen = strlen(request);
reqLen = (reqLen <= sizeof(struct3)) ? reqLen : sizeof(struct3);
memcpy(&struct3rec, request, reqLen );
printf("\n------ Struct3 Request ------\n");
printStruct(&struct3rec, sizeof(struct3));
cob_init(0,NULL);
CALLExternMethod2(&struct3rec); //Method overrides struct3Rec with the response
response = malloc(sizeof(struct3) + 1);
memset(response, 0x20, sizeof(struct3) );
memcpy(response, &struct3rec, sizeof(struct3));
response[sizeof(struct3)] = '\0';
printf("\n------ Struct3 Response ------\n");
printStruct(response, sizeof(struct3));
(*env)->ReleaseStringUTFChars(env, input, request);
jstring result = (*env)->NewStringUTF(env, response);
free(response);
printf("--- end of method2 JNI ---\n");
(*env)->PopLocalFrame(env,NULL);
return result;
}
C code (JNA)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "struct1.h"
#include "struct2.h"
#include "struct3.h"
#include "CALLExternMethod1s.h" //Interface External method
#include "CALLExternMethod2s.h" //Interface External method
void printStruct(void * structPar, int structSize) {
char buffer[structSize + 1];
memcpy(buffer, structPar, structSize);
buffer[structSize] = 0x00;
printf("{'%s'}\n", buffer);
}
char* method1(char *request){
struct1 struct1rec;
struct2 struct2rec;
char* response;
int reqLen = strlen(request);
reqLen = (reqLen <= sizeof(struct1)) ? reqLen : sizeof(struct1);
memcpy(&struct1rec, request, reqLen);
printf("\n------ Struct1 Request -------- \n");
printStruct(&struct1rec, sizeof(struct1));
CALLExternMethod1(&struct1rec, &struct2rec); //Method overrides struct2rec with the response
printf("\n------ Struct2 Response -------- \n");
printStruct(&struct2rec, sizeof(struct2));
response = malloc(sizeof(struct2) + 1);
memset(response, 0x20, sizeof(struct2) );
memcpy(response, &struct2rec, sizeof(struct2));
response[sizeof(struct2)] = '\0';
char* result;
memset(result, 0x20, sizeof(struct2));
result = response;
free(response);
return result;
}
char* method2(char *request){
struct3 struct3Rec;
char* response;
memcpy(&struct3Rec,request, sizeof(struct3));
printf("\n------ Struct3 Request -------- \n");
printStruct(&struct3Rec, sizeof(struct3));
CALLExternMethod2(&struct3Rec); //Method overrides struct3Rec with the response
printf("\n------ Struct3 Response -------- \n");
printStruct(&struct3Rec,sizeof(struct3));
response = malloc(sizeof(struct3) + 1);
memset(response, 0x20, sizeof(struct3) );
memcpy(response, &struct3Rec, sizeof(struct3));
response[sizeof(struct3)] = '\0';
char* result;
memcpy(result, response, sizeof(struct3));
return result;
}
int main(int argc, char** args){
return 0;
}
Java Call
(...)
static {
System.loadLibrary("libstuff");
}
public static synchronized native String method1(String struct);
(...)
CALLExternMethod1 and CALLExternMethod2 are not the problem. The issue happens even when there is fake response and methods are not used.
Anybody with the same issue?

Related

Returing data from JNI fuction to Android application code

I am developing an Android application for which I am using one native C library. This library is used for file decompression.
The definition of the native method is as follows:
public static native Long decompress(ByteBuffer src, ByteBuffer dst);
My application code to use this function is as follows:
try {
File inFile = new File(Environment.getExternalStorageDirectory().getPath() +"/1"); // source file
ByteBuffer buf = ByteBuffer.allocateDirect((int)inFile.length());
ByteBuffer buf_out = ByteBuffer.allocateDirect((int)inFile.length()*20);
InputStream is = new FileInputStream(inFile);
int b;
while ((b=is.read())!=-1) {
buf.put((byte)b);
}
Log.d("nims","source buffer zie"+buf.position());
File file = new File(Environment.getExternalStorageDirectory().getPath() +"/2");
// append or overwrite the file
boolean append = false;
FileChannel channel = new FileOutputStream(file, append).getChannel();
Long t = decompress(buf,buf_out); // t is some XYZ number
Log.d("nims","dest buffer zie"+buf_out.position()); // buf_out.position() returns 0
buf_out.flip();
// Writes a sequence of bytes to this channel from the given buffer.
channel.write(buf_out);
// close the channel
channel.close();
}
catch (IOException e) {
System.out.println("I/O Error: " + e.getMessage());
}
JNI code:
JNIEXPORT jlong JNICALL
Java_com_company_appName_MainActivity_decompress(JNIEnv* env, jclass cls, jobject src, jobject dst) {
uint8_t* src_buffer = (*env)->GetDirectBufferAddress(env,src);
const size_t src_size = (*env)->GetDirectBufferCapacity(env, src);
uint8_t* dst_buffer = (*env)->GetDirectBufferAddress(env,dst);
size_t dst_size = (*env)->GetDirectBufferCapacity(env, dst);
jlong test = _decode_buffer(dst_buffer, dst_size, src_buffer, src_size, NULL);
return test;
}
The destination buffer doesn't contain any data.
I have following questions:
How can I read the destination bytebuffer back from JNI code to application's code?
How can I write the destination bytebuffer data to a file?
I would appreciate any suggestion and thoughts on this topic.
EDIT 1:
size_t test = lzfse_decode_buffer(dst_buffer, dst_size, src_buffer, src_size, NULL);
ALOG("Size of test %d.",test); // output is 319488
ALOG("Size of test after casting %ld.",(jlong)test); // output is -125648933
//New code from stack overflow
jclass cls2 = (*env)->GetObjectClass(env, dst);
jmethodID limitId = (*env)->GetMethodID(env, cls2, "limit", "(I)Ljava/nio/Buffer;");
(*env)->CallObjectMethod(env, dst, limitId,(jlong) test);
jmethodID positionId = (*env)->GetMethodID(env, cls2, "position", "(I)Ljava/nio/Buffer;");
(*env)->CallObjectMethod(env, dst, positionId, 0);
EDIT 2:
size_t test = lzfse_decode_buffer(dst_buffer, dst_size, src_buffer, src_size, NULL);
ALOG("Size of test %d.",test); // output is 319488
ALOG("Size of test after casting %d.",(jint)test); // output is 319488
//New code from stack overflow
jclass cls2 = (*env)->GetObjectClass(env, dst);
jmethodID limitId = (*env)->GetMethodID(env, cls2, "limit", "(I)Ljava/nio/Buffer;");
(*env)->CallObjectMethod(env, dst, limitId,(jint) test);
jmethodID positionId = (*env)->GetMethodID(env, cls2, "position", "(I)Ljava/nio/Buffer;");
(*env)->CallObjectMethod(env, dst, positionId, 0);
When you write to DirectByteBuffer in C, this does not change the size (limit) and position
of the dst buffer. You must set these yourself. You can do it in native code:
jclass cls = (*env)->GetObjectClass(env, dst);
jmethodID limitId = (*env)->GetMethodID(env, cls, "limit", "(I)Ljava/nio/Buffer;");
(*env)->CallObjectMethod(env, dst, limitId, actual_size);
jmethodID positionId = (*env)->GetMethodID(env, cls, "position", "(I)Ljava/nio/Buffer;");
(*env)->CallObjectMethod(env, dst, positionId, 0);
This assumes that you can retrieve the actual number of bytes written to dst buffer from the _decode_buffer() function.
And you don't need flip().

Convert java.lang.Byte[] to string in Java

i am getting java.lang.Byte[] from c(jbyteArray in JNI) . How to convert this jbyteArray to string in java.
c function is
jbyteArray Java_eu_ratikal_helloc_MainActivity_getNameBytes(JNIEnv* env, jobject thiz) {
int n=0;
jstring na ="HelloAndroidString";
char* p = "HelloAndroidString";
while(*p++){
n++;
}
jbyteArray arr = (*env)->NewByteArray(env, n);
(*env)->SetByteArrayRegion(env,arr,0,n, (jbyte*)na);
char* b = (char*)arr;
return arr;
}
java code is
byte[] bytes = getNameBytes();
Getting compilation error like
Incompatible types
Required byte[]
Found java.lang.Byte[]
You need to return
public native byte[] getNamBytes();
but to convert it into a String you need to use new String e.g.
public String String getName() {
return new String(getNameBytes(), "UTF-8");
}

Android BSD sockets connection

I'm experiencing some issues while trying to connect BSD client socket to the server.
Socket creation and connecting are implemented with JNI. The actual connection is established via java code.
JNI part:
#include <jni.h>
#include <unistd.h>
#include <string.h>
#include <sys/endian.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
JNIEXPORT jint JNICALL Java_com_example_socketclinet_Native_socket
(JNIEnv *, jclass, jint, jint, jint);
JNIEXPORT jint JNICALL Java_com_example_socketclinet_Native_connect
(JNIEnv *, jclass, jint, jint, jint);
jint JNICALL Java_com_example_socketclinet_Native_socket
(JNIEnv *env, jclass cls, jint domain, jint type, jint protocol)
{
return socket(domain, type, protocol);
}
jint JNICALL Java_com_example_socketclinet_Native_connect
(JNIEnv *env, jclass cls, jint socket, jint address, jint port)
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(address);
addr.sin_port = htons(port);
return connect(socket, (const struct sockaddr *)&addr, sizeof(struct sockaddr_in));
}
Java native-bridge class:
class Native
{
static
{
System.loadLibrary("mylib");
}
public static final int SOCK_STREAM = 2;
public static final int AF_INET = 2;
public static native int socket(int domain, int type, int protocol);
public static native int connect(int socket, int address, int port);
}
Native class usage:
int socket = Native.socket(Native.AF_INET, Native.SOCK_STREAM, 0);
if (socket < 0)
{
System.err.println("Socket error: " + socket);
return;
}
byte[] address = { .... }; // 192.168.xxx.xxx
int addr = address[0] << 24 | address[1] << 16 | address[2] << 8 | address[3];
int port = ....;
int result = Native.connect(socket, addr, port);
if (result < 0)
{
System.err.println("Connection failed: " + result);
}
else
{
System.out.println("Connected");
}
The "connect" method always returns "0" even if there's no server running (both on device and simulator).
• I have "INTERNET" permission set with the manifest file (without it "socket" function returns -1)
• The same code works perfectly fine on iOS and Mac OS.
• Testing environment: Nexus 5 (4.4.4), android-ndk-r10d
Any help will greatly appreciated!
byte[] is signed in Java, which means your |addr| computation is likely wrong. I suspect you are connecting to a broadcast address, which will always succeed by definition.
Try printing the address from native code through to verify that, otherwise, try to replace the computation with:
int addr = (address[0] & 255) << 24 |
(address[1] & 255) << 16 |
(address[2] & 255) << 8 |
(address[3] & 255);
To see if that solves the problem.

JNI NewByteArray memory leak

I have a Java method that process a bitmap and returns a String.
When I call this method from JNI (VS 2010) it works, but if I call this method many times,
the memory of the process grown up until crash.
The instruction that use a lot of memory is:
jbyteArray jBuff = _env->NewByteArray(b->Length);
My code:
static jobject staticArray=0;
System::String^ MyClass::ExecuteJavaMethod(System::Drawing::Bitmap^ bmp)
{
JNIEnv *_env;
System::String^ out;
unsigned const char * buff;
int res = jvm->AttachCurrentThread((void **)&_env, NULL);
if (jvm->GetEnv((void**) &_env, JNI_VERSION_1_6) != JNI_OK)
{
return "GetEnv ERROR";
}
//save the bitmap in the stream
MemoryStream^ ms = gcnew MemoryStream();
bmp->Save(ms, ImageFormat::Bmp);
//get the bitmap buffer
array<unsigned char>^b = ms->GetBuffer() ;
//unmanaged conversion
buff = GetUnmanaged(b,b->Length);
//fill the buffer
jbyteArray jBuff = _env->NewByteArray(b->Length);
_env->SetByteArrayRegion(jBuff, 0, b->Length, (jbyte*) buff);
//call the java method
jstring str = (jstring) _env->CallStaticObjectMethod ( Main,
javaMethod,
jBuff);
// _env->ReleaseByteArrayElements(jBuff,(jbyte*)buff), 0); //NOT WORKING
//staticArray= _env->NewGlobalRef(jBuff); NOT
//_env->DeleteLocalRef(jBuff); WORKING
//return the string result of the java method
return gcnew String(env->GetStringUTFChars(str, 0));
}
the answer is: _env->DeleteLocalRef(jBuff);
You didn't call DetachCurrentThread() for each AttachCurrentThread(), which is requested in Java Native Interface Specification. That makes the local references (jBuff and str) unable to be freed automatically. Also, the const char* fetched through GetStringUTFChars() needs to be released.
The correct way is change
return gcnew String(env->GetStringUTFChars(str, 0));
into
const char* cstr = env->GetStringUTFChars(str, 0);
System::String^ retstr = gcnew String(cstr);
env->ReleaseStringUTFChars(str, cstr);
jvm->DetachCurrentThread();
return retstr;

sending UTF chars to java from c++ using jni

I want to send Hangul (Korean symbols using UTF) text from C to JAVA.
But JAVA gets incorrect results
Example:
JNIEXPORT jstring JNICALL Java_get_1term
(JNIEnv *env, jobject, jint termInd)
{
const char *str = "음뮤원음직음원샘";
return (env)->NewStringUTF(str);
}
but in that case JAVA got incorrect string.
I couldn't find answer to my question in other posts, if there is same question please give me link to them
try with this (taken and adapted from here):
jstring WindowsToJstring(JNIEnv* pEnv, char* cstr) {
jstring retJstring = NULL;
int slen = strlen(cstr);
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)cstr, slen, NULL, 0 );
unsigned short* tempbuffer = (unsigned short *)malloc( length*2 + 1 );
MultiByteToWideChar( CP_ACP, 0, (LPCSTR)cstr, slen, (LPWSTR)tempbuffer, length );
retJstring = (pEnv)->NewString((jchar*)tempbuffer, length );
free( tempbuffer );
return retJstring;
}
EDIT As correctly noted by #Kerrek SB this is a Windows only solution

Categories

Resources