0

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?

Julia Bel
  • 337
  • 4
  • 18
  • In the JNI version you are popping a local reference frame which afaik also contains the result, without saving the result. -- The last `memset`/`memcpy` in your JNA version uses an uninitialized pointer which is UB. – Jorn Vernee Jun 19 '17 at 13:51
  • @Jorn Vernee Regarding the popping local reference, even after that, I can get the results in Java. Also, if I took it off, the response is the same (and the issue as well). The last memset/memcpy, aren't they necessary? I am just preparing the response to fits with a char* value (with \0 in the end). – Julia Bel Jun 19 '17 at 14:06
  • Yes, but you actually need to initialize the pointer (e.g. `char* result = malloc(sizeof(struct3))`), now it just points to a more or less random memory location. -- If you remove the `PopLocalFrame` I can't see anything wrong with that code. – Jorn Vernee Jun 19 '17 at 14:13
  • Honestly, just return `response`, without freeing it. – Jorn Vernee Jun 19 '17 at 14:20
  • Where is the reference to gnu-cobol? – Simon Sobisch Jun 19 '17 at 17:07
  • @JornVernee Unfortunatelly, your resolutions didn't work. I am getting the same issue. – Julia Bel Jun 19 '17 at 20:50
  • @SimonSobisch gnu-cobol is related because the ExternalMethod used were cobol and it was transformed to C using GnuCobol. Maybe any specialist could explain the error in this POV. – Julia Bel Jun 19 '17 at 20:52
  • @JuliaBel: In this case please check if it works with "very simple" external methods written directly in C. If it does you have a problem at the COBOL end, which can surely be solved when `cobc --version` and the compiler flags used for compiling the external methods. You didn't changed them post-generation, did you? – Simon Sobisch Jun 20 '17 at 21:48
  • @SimonSobisch I took off the call to ExternalMethod C (translated from COBOL) and the problem persisted. I even used a new Java, like a mediator between the official java application and C, but the issue persists. – Julia Bel Jun 28 '17 at 18:14
  • @JuliaBel: So there's no GnuCOBOL in and you still get the error, did I understood this correctly? – Simon Sobisch Jun 28 '17 at 19:37
  • @Simon Sobisch Actually, it's using (I edited the post because I found something) cob_init(0,NULL), to setup the environment to be able to use ExternalMethod (translated from Cobol). When I don't use cob_init(0,NULL), I don't have issues. With it, I do have. Do you know if Gnu_Cobol or cob_init could have issues working with JNI? Because the error that I am having is coming from cob_init. – Julia Bel Jun 29 '17 at 13:30

0 Answers0