字符*损坏跨JNI调用 [英] Char* Corrupted Across JNI Calls

查看:159
本文介绍了字符*损坏跨JNI调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正与在Android(谷歌玻璃特别是)一个C库(librtmp),由SWIG创建的绑定。

当我打电话包含一个char *一个struct一个本地方法,从这个方法返回,并调用另一个本地方法中,char *不会有这相同的数据,很多时候数据将显示为空,但有时它会包含java或项目的路径,或随机文本(例如部分: glassvideostreamer /溴化锂 Zunk + 太阳/ * )也有时会包含非有效的UNI code code点。 指针本身不断指向的JNI调用同一个内存位置,并且是正确的,当第一款原生方法退出,并损坏当它进入另一个本地方法。

包装纸在天然功能这两种方法,然后调用该函数工作正常,但随后调用另一个本地方法的数据将不再是在存储位置时

下面是我的code:

test.i

 %模块test_wrapper
#定义NO_CRYPTO
/ *以下部分内容都会被逐字加入到.CXX包装文件* /
%{
#包括rtmp.h
%}
测试* Alloc_Test();
无效Init_Test(测试* T,字符*数据,INT LEN);
无效Test_String(测试* T);
无效Init_And_Test_String(测试* T,字符*数据,INT LEN);
 

rtmp.h

  typedef结构试验{
    字符*数据;
    INT LEN;
  } 测试;
  测试* Alloc_Test();
  无效Init_Test(测试* T,字符*数据,INT LEN);
  无效Test_String(测试* T);
  无效Init_And_Test_String(测试* T,字符*数据,INT LEN);
 

rtmp.c

 测试* Alloc_Test(){
  返回释放calloc(的sizeof(试验));
}
无效Init_Test(测试* T,字符*数据,INT LEN){
  T->数据=数据;
  T->的len = LEN;
  __android_log_print(ANDROID_LOG_DEBUG,TEST,字符串:%* S(指针:%P),T-> LEN,叔>的数据,T);
}
无效Test_String(测试* T){
 __android_log_print(ANDROID_LOG_DEBUG,TEST,%字符串:%* S(指针:%P),T-> LEN,叔>的数据,T);
}
无效Init_And_Test_String(测试* T,字符*数据,INT LEN){
  Init_Test(T,数据的len);
  Test_String(T);
}
 

最终值(C),这里的生成痛饮绑定 librtmp_wrap.c

  SWIGEXPORT jlong​​ JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Alloc_1Test(JNIEnv的* jenv,JCLASS JCLS){
  jlong​​ jresult = 0;
  测试*结果= 0;

  (无效)jenv;
  (无效)JCLS;
  结果=(测试*)Alloc_Test();
  *(试验**)及jresult =结果;
  返回jresult;
}


SWIGEXPORT无效JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Init_1Test(JNIEnv的* jenv,JCLASS JCLS,jlong​​ jarg1,的jstring jarg2,jint jarg3){
  测试* ARG1 =(测试*)0;
  字符* ARG2 =(字符*)0;
  INT ARG3;

  (无效)jenv;
  (无效)JCLS;
  ARG1 = *(试验**)及jarg1;
  ARG2 = 0;
  如果(jarg2){
    ARG2 =(字符*)(* jenv) - > GetStringUTFChars(jenv,jarg2,0);
    如果回报(ARG2!);
  }
  参数3 =(INT)jarg3;
  Init_Test(ARG1,ARG2,ARG3);
  如果(ARG2)(* jenv) - > ReleaseStringUTFChars(jenv,jarg2,(为const char *)ARG2);
}


SWIGEXPORT无效JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Test_1String(JNIEnv的* jenv,JCLASS JCLS,jlong​​ jarg1){
  测试* ARG1 =(测试*)0;

  (无效)jenv;
  (无效)JCLS;
  ARG1 = *(试验**)及jarg1;
  Test_String(ARG1);
}


SWIGEXPORT无效JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Init_1And_1Test_1String(JNIEnv的* jenv,JCLASS JCLS,jlong​​ jarg1,的jstring jarg2,jint jarg3){
  测试* ARG1 =(测试*)0;
  字符* ARG2 =(字符*)0;
  INT ARG3;

  (无效)jenv;
  (无效)JCLS;
  ARG1 = *(试验**)及jarg1;
  ARG2 = 0;
  如果(jarg2){
    ARG2 =(字符*)(* jenv) - > GetStringUTFChars(jenv,jarg2,0);
    如果回报(ARG2!);
  }
  参数3 =(INT)jarg3;
  Init_And_Test_String(ARG1,ARG2,ARG3);
  如果(ARG2)(* jenv) - > ReleaseStringUTFChars(jenv,jarg2,(为const char *)ARG2);
}
 

在Java端:我们只是生成SWIGTYPE_p测试包的结构指针和code调用JNI函数: test_wrapperJNI.java

 公共类test_wrapperJNI {
  公共最后静态本地长Alloc_Test();
  公共最后静态本地无效Init_Test(长jarg1,串jarg2,INT jarg3);
  公共最后静态本地无效Test_String(长jarg1);
  公共最后静态本地无效Init_And_Test_String(长jarg1,串jarg2,INT jarg3);
}
 

test_wrapper.java

 公共类test_wrapper {
  公共静态SWIGTYPE_p_test Alloc_Test(){
    长CPTR = test_wrapperJNI.Alloc_Test();
    返程(CPTR == 0)?空:新SWIGTYPE_p_test(CPTR,假);
  }

  公共静态无效Init_Test(SWIGTYPE_p_test T,字符串数据,INT LEN){
    test_wrapperJNI.Init_Test(SWIGTYPE_p_test.getCPtr(吨),数据,LEN);
  }

  公共静态无效Test_String(SWIGTYPE_p_test T){
    test_wrapperJNI.Test_String(SWIGTYPE_p_test.getCPtr(吨));
  }

  公共静态无效Init_And_Test_String(SWIGTYPE_p_test T,字符串数据,INT LEN){
    test_wrapperJNI.Init_And_Test_String(SWIGTYPE_p_test.getCPtr(吨),数据,LEN);
  }

}
 

把他们放在一起,你可以获得:

 的System.loadLibrary(TEST);
SWIGTYPE_p_test测试= test_wrapper.Alloc_Test();
test_wrapper.Init_Test(试验,将这个字符串保持不变?,31);
test_wrapper.Test_String(试验);

测试= test_wrapper.Alloc_Test();
test_wrapper.Init_And_Test_String(考这个字符串将保持不变,30);
 

它得到这个结果(在logcat中):

 一十二月5日至11日:27:33.198 4568-4568 / atellis.glassvideostreamer D / dalvikvm:试图加载LIB /data/app-lib/atellis.glassvideostreamer-1/libTEST。所以0x41b597b0
12月5号至11日:27:33.198 4568-4568 / atellis.glassvideostreamer D / dalvikvm:添加LIB /data/app-lib/atellis.glassvideostreamer-1/libTEST.so 0x41b597b0共享
12月5号至11日:27:33.198 4568-4568 / atellis.glassvideostreamer D / dalvikvm:没有JNI_OnLoad在/data/app-lib/atellis.glassvideostreamer-1/libTEST.so 0x41b597b0发现,跳绳的init
12月5号至11日:27:38.128 4568-4568 / atellis.glassvideostreamer D / TEST:字符串:请问这个字符串保持不变? (指针:0x59564088)
12月5号至11日:27:39.940 4568-4568 / atellis.glassvideostreamer D / TEST:字符串:(指针:0x59564088)
12月5号至11日:27:41.261 4568-4568 / atellis.glassvideostreamer D / TEST:字符串:这个字符串将保持不变(指针:0x59565948)
12月5号至11日:27:41.261 4568-4568 / atellis.glassvideostreamer D / TEST:字符串:这个字符串将保持不变(指针:0x59565948)
 

在这种情况下,字符串变成一片空白!正如我上面提到的,虽然,它有时会含有文件路径或随机文本。

解决方案

  typedef结构试验{
    字符*数据;
    INT LEN;
} 测试;
 

本规定没有空间实际存储的字符串数据,而只是一个指针来保存它的地址。

您似乎在实践中,在可能的临时预约的各种函数参数的内存指向它,这是行不通的内存可以在以后重新利用。

 无效Init_Test(测试* T,字符*数据,INT LEN){
    T->数据=数据;
 

其实,你明确地释放你所说的内存:

  Init_And_Test_String(ARG1,ARG2,ARG3);
如果(ARG2)(* jenv) - > ReleaseStringUTFChars(jenv,jarg2,(为const char *)ARG2);
 

您必须明确保留内存来存放字符串,而复制的任何的临时的存储在那里。

I'm working with a C library (librtmp) on android (Google glass specifically), with bindings created by SWIG.

When I call a native method with a struct containing a char*, return from that method, and call another native method, the char* will not have the same data in it, many times the data will appear to be null, but sometimes it will contain parts of the java or project path or random text (ex: glassvideostreamer/libr, Zunk+, sun/* ) it will also sometimes contain non-valid unicode code points. The pointer itself keeps pointing to the same memory location between JNI calls, and is correct when the first native method exits, and corrupted when it enters another native method.

Wrapping both methods in a native function and then calling that function works correctly, but then when calling another native method the data will no longer be at the memory location.

Here's my code:

test.i

%module test_wrapper
#define NO_CRYPTO
/* Anything in the following section is added verbatim to the .cxx wrapper file*/
%{
#include "rtmp.h"
%}
test* Alloc_Test();
void Init_Test(test* t, char* data, int len);
void Test_String(test* t);
void Init_And_Test_String(test* t, char* data, int len);

rtmp.h

  typedef struct test {
    char* data;
    int len;
  } test;
  test* Alloc_Test();
  void Init_Test(test* t, char* data, int len);
  void Test_String(test* t);
  void Init_And_Test_String(test* t, char* data, int len);

rtmp.c

test* Alloc_Test(){
  return calloc(sizeof(test));
}
void Init_Test(test* t, char* data, int len){
  t->data = data;
  t->len = len;
  __android_log_print(ANDROID_LOG_DEBUG,"TEST", "String: %.*s  (pointer: %p)", t->len, t->data, t);
}
void Test_String(test* t){
 __android_log_print(ANDROID_LOG_DEBUG,"TEST","%String: %.*s  (pointer: %p)", t->len, t->data, t);
}
void Init_And_Test_String(test* t, char* data, int len){
  Init_Test(t, data, len);
  Test_String(t);
}

finally (for c) here's the generated swig bindings librtmp_wrap.c

SWIGEXPORT jlong JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Alloc_1Test(JNIEnv *jenv, jclass jcls) {
  jlong jresult = 0 ;
  test *result = 0 ;

  (void)jenv;
  (void)jcls;
  result = (test *)Alloc_Test();
  *(test **)&jresult = result; 
  return jresult;
}


SWIGEXPORT void JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Init_1Test(JNIEnv *jenv, jclass jcls, jlong jarg1, jstring jarg2, jint jarg3) {
  test *arg1 = (test *) 0 ;
  char *arg2 = (char *) 0 ;
  int arg3 ;

  (void)jenv;
  (void)jcls;
  arg1 = *(test **)&jarg1; 
  arg2 = 0;
  if (jarg2) {
    arg2 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg2, 0);
    if (!arg2) return ;
  }
  arg3 = (int)jarg3; 
  Init_Test(arg1,arg2,arg3);
  if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);
}


SWIGEXPORT void JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Test_1String(JNIEnv *jenv, jclass jcls, jlong jarg1) {
  test *arg1 = (test *) 0 ;

  (void)jenv;
  (void)jcls;
  arg1 = *(test **)&jarg1; 
  Test_String(arg1);
}


SWIGEXPORT void JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Init_1And_1Test_1String(JNIEnv *jenv, jclass jcls, jlong jarg1, jstring jarg2, jint jarg3) {
  test *arg1 = (test *) 0 ;
  char *arg2 = (char *) 0 ;
  int arg3 ;

  (void)jenv;
  (void)jcls;
  arg1 = *(test **)&jarg1; 
  arg2 = 0;
  if (jarg2) {
    arg2 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg2, 0);
    if (!arg2) return ;
  }
  arg3 = (int)jarg3; 
  Init_And_Test_String(arg1,arg2,arg3);
  if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);
}

on the java side: we just have the generated SWIGTYPE_p test that wraps the struct pointer and code that calls the JNI functions: test_wrapperJNI.java

public class test_wrapperJNI {
  public final static native long Alloc_Test();
  public final static native void Init_Test(long jarg1, String jarg2, int jarg3);
  public final static native void Test_String(long jarg1);
  public final static native void Init_And_Test_String(long jarg1, String jarg2, int jarg3);
}

and test_wrapper.java

public class test_wrapper {
  public static SWIGTYPE_p_test Alloc_Test() {
    long cPtr = test_wrapperJNI.Alloc_Test();
    return (cPtr == 0) ? null : new SWIGTYPE_p_test(cPtr, false);
  }

  public static void Init_Test(SWIGTYPE_p_test t, String data, int len) {
    test_wrapperJNI.Init_Test(SWIGTYPE_p_test.getCPtr(t), data, len);
  }

  public static void Test_String(SWIGTYPE_p_test t) {
    test_wrapperJNI.Test_String(SWIGTYPE_p_test.getCPtr(t));
  }

  public static void Init_And_Test_String(SWIGTYPE_p_test t, String data, int len) {
    test_wrapperJNI.Init_And_Test_String(SWIGTYPE_p_test.getCPtr(t), data, len);
  }

}

putting it all together you get:

System.loadLibrary("TEST");
SWIGTYPE_p_test test = test_wrapper.Alloc_Test();
test_wrapper.Init_Test(test, "Will this string stay the same?", 31);
test_wrapper.Test_String(test);

test = test_wrapper.Alloc_Test();
test_wrapper.Init_And_Test_String(test, "This string will stay the same", 30);

which gets this result (in logcat):

05-11 12:27:33.198    4568-4568/atellis.glassvideostreamer D/dalvikvm﹕ Trying to load lib /data/app-lib/atellis.glassvideostreamer-1/libTEST.so 0x41b597b0
05-11 12:27:33.198    4568-4568/atellis.glassvideostreamer D/dalvikvm﹕ Added shared lib /data/app-lib/atellis.glassvideostreamer-1/libTEST.so 0x41b597b0
05-11 12:27:33.198    4568-4568/atellis.glassvideostreamer D/dalvikvm﹕ No JNI_OnLoad found in /data/app-lib/atellis.glassvideostreamer-1/libTEST.so 0x41b597b0, skipping init
05-11 12:27:38.128    4568-4568/atellis.glassvideostreamer D/TEST﹕ String: Will this string stay the same?  (pointer: 0x59564088)
05-11 12:27:39.940    4568-4568/atellis.glassvideostreamer D/TEST﹕ String:   (pointer: 0x59564088)
05-11 12:27:41.261    4568-4568/atellis.glassvideostreamer D/TEST﹕ String: This string will stay the same  (pointer: 0x59565948)
05-11 12:27:41.261    4568-4568/atellis.glassvideostreamer D/TEST﹕ String: This string will stay the same  (pointer: 0x59565948)

In this case the string becomes blank! As I mentioned above though, it will sometime contain file paths or random text.

解决方案

typedef struct test {
    char* data;
    int len;
} test;

This specifies no space to actually store the the string data, but merely a pointer to hold its address.

You seem in practice to be pointing it at the memory of various function arguments of likely temporary reservation, and that will not work as that memory can be re-purposed later.

void Init_Test(test* t, char* data, int len){
    t->data = data;

In fact, you explicitly release your claim to that memory:

Init_And_Test_String(arg1,arg2,arg3); 
if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);

You must explicitly reserve memory to hold the string, and copy from any temporary storage to there.

这篇关于字符*损坏跨JNI调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆