Char* 在 JNI 调用中损坏
Char* Corrupted Across JNI Calls
我正在 android(特别是 Google glass)上使用 C 库 (librtmp),绑定由 SWIG 创建。
当我使用包含 char* 的结构调用本机方法时,return 从该方法调用另一个本机方法时,char* 中的数据不相同,数据是数据的很多倍将显示为空,但有时它会包含部分 java 或项目路径或随机文本(例如:glassvideostreamer/libr
、Zunk+
、sun/*
)它有时也会包含无效的 unicode 代码点。
指针本身在 JNI 调用之间一直指向相同的内存位置,并且在第一个本机方法退出时是正确的,而在它进入另一个本机方法时损坏。
将这两个方法包装在一个本机函数中,然后调用该函数可以正常工作,但是当调用另一个本机方法时,数据将不再位于内存位置。
这是我的代码:
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);
}
最后(对于 c)这是生成的 swig 绑定
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);
}
在 java 方面:我们只有生成的 SWIGTYPE_p 测试包装了结构指针和调用 JNI 函数的代码:
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);
}
和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);
}
}
把它们放在一起你得到:
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);
得到这个结果(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)
在这种情况下字符串变为空白!正如我上面提到的,它有时会包含文件路径或随机文本。
typedef struct test {
char* data;
int len;
} test;
这没有指定 space 来实际存储字符串 data
,而只是一个指针来保存它的地址。
实际上,您似乎将其指向可能临时保留的各种函数参数的内存,这不会起作用,因为该内存稍后可以重新调整用途。
void Init_Test(test* t, char* data, int len){
t->data = data;
事实上,您明确释放了对该内存的声明:
Init_And_Test_String(arg1,arg2,arg3);
if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);
您必须显式保留内存来保存字符串,并从任何临时存储空间复制到那里。
我正在 android(特别是 Google glass)上使用 C 库 (librtmp),绑定由 SWIG 创建。
当我使用包含 char* 的结构调用本机方法时,return 从该方法调用另一个本机方法时,char* 中的数据不相同,数据是数据的很多倍将显示为空,但有时它会包含部分 java 或项目路径或随机文本(例如:glassvideostreamer/libr
、Zunk+
、sun/*
)它有时也会包含无效的 unicode 代码点。
指针本身在 JNI 调用之间一直指向相同的内存位置,并且在第一个本机方法退出时是正确的,而在它进入另一个本机方法时损坏。
将这两个方法包装在一个本机函数中,然后调用该函数可以正常工作,但是当调用另一个本机方法时,数据将不再位于内存位置。
这是我的代码:
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);
}
最后(对于 c)这是生成的 swig 绑定
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);
}
在 java 方面:我们只有生成的 SWIGTYPE_p 测试包装了结构指针和调用 JNI 函数的代码:
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);
}
和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);
}
}
把它们放在一起你得到:
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);
得到这个结果(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)
在这种情况下字符串变为空白!正如我上面提到的,它有时会包含文件路径或随机文本。
typedef struct test {
char* data;
int len;
} test;
这没有指定 space 来实际存储字符串 data
,而只是一个指针来保存它的地址。
实际上,您似乎将其指向可能临时保留的各种函数参数的内存,这不会起作用,因为该内存稍后可以重新调整用途。
void Init_Test(test* t, char* data, int len){
t->data = data;
事实上,您明确释放了对该内存的声明:
Init_And_Test_String(arg1,arg2,arg3);
if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);
您必须显式保留内存来保存字符串,并从任何临时存储空间复制到那里。