简体   繁体   中英

Non-deterministic return values (string type) from calling native C++ functions through JNA

problem description:

My project is JAVA but I want to call a C++ function, which takes a string as input and output another string after process. I apply JNA to do this work, and String and char* are mapping types from JAVA to C++.(During the processing, I need std::string as intermediate type, the simplyfied code is given out in detail.)

The program runs well, when the input string is not long. However, when I increase the length of the string(here, I duplicate "test sentence..." for 6 times), things began strange. I can see the string is pass in C++ program(successfully print out), BUT I received an empty string in JAVA, which means it fails to return the string. What's more, the times of while loop is different on each excution(print out different count when break the loop).

Then,

1. What's wrong with the length? Is there any limitation in JNA?

2. Can I reach my goal and how to pass string in JNA correctly?(BTW, I tried Pointer things, but it doesn't work)

Thanks ahead, here is my code and some enviroment details

CODE ON C++ SIDE>>>>>>>>>>>test.cpp

#include<iostream>
using namespace std;
extern "C" __attribute__((visibility("default"))) const char* SeudoCall(const char* input); 
const char* SeudoCall(const char* str){
    std::string input(str);
    std::cout<<"in C:"<<input<<std::endl;
    return input.c_str();
}

COMPILE C++ LIBRARY>>>>>>>>>

g++ test.cpp -fpic -shared -o libtest.so

CODE ON JAVA SIDE>>>>>>>>>>>

import com.sun.jna.Library;
import com.sun.jna.Native;
public class TestSo {
    public interface LgetLib extends Library {
        LgetLib INSTANCE = (LgetLib) Native.loadLibrary("test", LgetLib.class);
        String SeudoCall(String input);
    }
    public String SeudoCall(String input){
        return LgetLib.INSTANCE.SeudoCall(input);
    }
    public static void main(String[] args) {
        TestSo ts = new TestSo();
        String str = "test sentence...test sentence...test sentence...test sentence...test sentence...test sentence...";
        String retString;
        int count=0;
        while(true){
            System.out.println("count:"+(++count));
            retString=ts.SeudoCall(str);
            System.out.println("in JAVA:"+retString);
            if(retString.equals("")){
                System.out.println("break");
                break;
            }
        }
    }
}

RUN DETAIL>>>>>>>>>>>

Intel Core i7-4790 3.60GHz
gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)
JNA 4.1.0
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)

You have a problem with your C++ code right away. You are returning a pointer to a local std::string that will be destroyed when the function exists. Thus you are introducing undefined behavior.

In other words, your function would be buggy even if the application were all C++, so it isn't solely a Java/JNA/C++ issue, but a C++ issue in itself.

const char* SeudoCall(const char* str){
    std::string input(str);
    std::cout<<"in C:"<<input<<std::endl;
    return input.c_str();  // <-- this is no good.
}

The c_str() is tied to the local variable input . When the function exits, the destructor for input takes place, taking along with it the c_str() that represented the string.

To fix this, you have to return a string back to Java that will be "alive" after the function returns. I do not know JNA, but for JNI, you use the JNI NewStringUTF function to create a string that will be returned as a jstring .

Maybe this link will help you:

How to return char * aarr= new char[200] from C++ to Java using JNA

The program runs well, when the input string is not long. However, when I increase the length of the string(here, I duplicate "test sentence..." for 6 times), things began strange. I can see the string is pass in C++ program(successfully print out), BUT I received an empty string in JAVA, which means it fails to return the string. What's more, the times of while loop is different on each excution(print out different count when break the loop).

What you are witnessing is undefined behavior . The pointer returned from your C++ function may be pointing to the memory that holds the characters, but it is not to be relied on, as your testing is showing you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM