Search code examples
androidc++java-native-interface

issues with memcpy on android when using offset for the source


I am working on an android app using JNI.

I keep sending byte[] from java and it arrives as a jbyteArray in cpp.

To get from the jbyteArray to a signed char* i use this function:

jbyte* content_array = (env)->GetByteArrayElements(array,NULL);

(jbyte* is just a typedef of signed char*)

Now i did run into problems when trying to access the data at the signed char* pointer at later times. It think at some point the java garbage collector kicks in and frees the memory, so i can no longer access it.

To work around this issue, i am now copying the incoming data like this:

    // newJavaByteData is the signed char* coming in from java
    signed char* buffer = new signed char[length];
    memcpy(buffer, newJavaByteData, length);
    //javaByteData is a std::vector<signed char*>
    javaByteData.push_back(buffer);

So far so good. At later frames i can read the data and when i do not need it any more, i delete it like this:

        int frame_cnt=0;
        while(frame_cnt<javaByteData.size()){
            delete javaByteData[frame_cnt++];
        }
        javaByteData.clear();

Now i need to extract chunks of bytes from this data. Again i am using memcpy to extract the needed portion of the bytes.

This time i need to apply a offset to the source-pointer

    char* extractedBytes[lengthOfBytes];
    //originalJavaData is the signed char* i did alloc and memcpy into earlier
    memcpy(extractedBytes, &originalJavaData[offset], lengthOfBytes* sizeof(char));

This is working well, until its not :(

I can extract data this way, but when the amount of bytes i extract exceed some limit, i am getting this error:

SIGSEGV (signal SIGSEGV: invalid address (fault address: 0x53))

The fault address varies with each time i run the app message.

I am not yet sure what the limit is, but i can extract 262144 bytes (256x256x4) just fine, while extracting 1048576 bytes (1024x1024x4) is causing the crash / signal.

I was thinking the issue was that i am running out of memory in the cpp thread, but i can happily alloc more memory. just the memcpy is failing.

I think i could set up a eventHandler for the SIGSEGV signals, but i have no experience with that, and also i already tracked the issue down to the usage of memcpy, so i hope it just a thing i am doing wrong with memcpy.

I am thinking that maybe its a problem with memory not aligned correctly and thus the memcpy is failing due to the fact that i add the offset to the source-pointer.

Any help would be greatly appreciated.


Solution

  • OK. I found the problem.

    It seem that i was running out of stack memory, while when i use heap memory i am good to go.

    So instead of this lines:

    char* extractedBytes[lengthOfBytes];
    //originalJavaData is the signed char* i did alloc and memcpy into earlier
    memcpy(extractedBytes, &originalJavaData[offset], lengthOfBytes* sizeof(char));
    

    i now have this:

    char* extractedBytes = new char[lengthOfBytes];
    //originalJavaData is the signed char* i did alloc and memcpy into earlier
    memcpy(extractedBytes, &originalJavaData[offset], lengthOfBytes* sizeof(char));
    

    memcpy is now doing its job and extracts portions of the signed char* without complaining.

    Of course by allocating the memory on the heap, i now have to take care of disposing my data later.

    On a sidenote: I stopped copying the incoming data myself, and instead of GetByteArrayElements i am now using GetByteArrayRegion which is doing the copying for me.

    Hope i do not get downvoted for answering my own question again. For me this is a valid solution to my problem.