10835


JNAを用いてJavaからC++のライブラリの関数を使い、戻り値としてfloatとStringの配列を得たいのですが、floatは全く違う値になり、Stringは読み出そうとするとSIGSEGVが発生します。関数の呼び出しや、引数に与えた構造体がC++側で読めていることは確認しています。[このサイト](http://www.eshayne.com/jnaex/example14.html)などを参考に以下のようなコードを作成しています。どうすればエラーなく処理できるでしょうか？

c++

[code]

    typedef struct result {
        float* score;
        char** value;
    } result;
    
    result myfunc(){
        result *res = (result)malloc(sizeof(result));
        memset(res, 0, sizeof(result));
    
        (*res).score = (float*)malloc(sizeof(float) * 10);
        memset((*res).score, 0, sizeof(float) * 10);
        (*res).value = (char**)malloc(sizeof(char*) * 10);
    
        for (size_t i = 0; i < 10; ++i) {
            (*res).score[i] = getscore(i);
    
            char* val = getvalue(i);
            (*res).value[i] = (char *)malloc(sizeof(val));
            memset((*res).value[i], 0, sizeof(val));
            strcpy((*res).value[i], val);
        }
      /* ここでres.score[i], res.value[i]を出力すると正常な値になっているのを確認 */
    }
    
[/code]

java

[code]

    import com.sun.jna.*;
    import com.sun.jna.ptr.*;
    
    public interface MyLib extends Library {
        public static class result extends Structure {
            public static class ByValue extends result implements Structure.ByValue {}
            public Pointer value; // char**
            public Pointer score; // float*
            protected List getFieldOrder() {
                return Arrays.asList(new String[]{
                        "value", "score",
                });
            }
        }
    
        MyLib INSTANCE = (MyLib) Native.loadLibrary("mylib", MyLib.class);
        public result.ByValue myfunc();
    }
    
    public static void main(String[] args) {
        MyLib.result.ByValue res = MyLib.INSTANCE.myfunc();
    
        for(int i = 0; i < 10; i++){
            float score = res.score.getFloat(i * Native.getNativeSize(Float.TYPE));
            System.out.println(score); // 値が異なる
        }
    
        String[] strs = res.value.getStringArray(0, 10);// SIGSEGVが発生
        for (String s: strs){
            if(s != null){
                System.out.println(s);
            }
        }
    }
    
[/code]


CC BY-SA 3.0
2015-06-01T05:25:19.800
10832
2015-06-01T09:06:11.587
2015-06-01T09:06:11.587
49
9947
question
java c++
JNAでC++から文字列を受け取る


リンク先のサンプルのは、Cの構造体配列をそのままJavaから得る場合のサンプルです。  
Java から安全に参照可能な構造体配列を取るのであれば、自分でインスタンスを作らなければなりません。例えば String の配列であれば以下の通り。

[code]

    ret= (jobjectArray)env->NewObjectArray(3,
         env->FindClass("java/lang/String"),
         env->NewStringUTF(""));
    for(i=0; i<3; i++) {
        env->SetObjectArrayElement(ret, i, env->NewStringUTF("こんにちわ世界"));  
    }  
    
[/code]

これをご自分の構造体をクラスとしてwrapした物で置き換えると出来上がるはずです。


CC BY-SA 3.0
2015-06-01T06:27:57.367
10835
2015-06-01T06:27:57.367
440
10832
answer


C++ myfunc()のコード見ただけですが気になったところ

[code]

    (*res).value[i] = (char *)malloc(sizeof(val)); 
    
[/code]

これだと 「char *」のサイズ分しか確保できてないので getvalue()
の戻り値次第ですがstrcpy()実行時にバッファーオーバフローを起こしてる気がします。

[code]

    (*res).value[i] = (char *)malloc(sizeof(char)*(strlen(val)+1)); 
    
[/code]


CC BY-SA 3.0
2015-06-01T07:52:04.770
10837
2015-06-01T07:58:05.327
2015-06-01T07:58:05.327
7343
7343
10832
answer