如果还有超过 2 个 jint 参数,则传入的字符串参数会导致 JNI 函数崩溃应用程序
Incoming string arguments cause JNI function to crash app if there are more than 2 jint arguments as well
我遇到了一个非常奇怪的问题。我有一个这样定义的 JNI 函数:
void Java_com_example_app_JNITest
(
JNIEnv* env,
jobject thiz,
jint jSlotID,
jint ulPinLen,
jstring strStr1,
jstring strStr2,
jstring strStr3,
jstring strStr4
)
{
char* pszPin;
char* pszStr1;
char* pszStr2;
char* pszStr3;
char* pszStr4;
int strLen;
strLen = (*env)->GetStringUTFLength(env, strStr1);
LOGD("copying Str1, len = %d", strLen);
pszStr1 = (char*) (*env)->GetStringUTFChars(env, strStr1, NULL);
LOGD(pszStr1);
strLen = (*env)->GetStringUTFLength(env, strStr2);
LOGD("copying Str2, len = %d", strLen);
pszStr2 = (char*) (*env)->GetStringUTFChars(env, strStr2, NULL);
LOGD(pszStr2);
strLen = (*env)->GetStringUTFLength(env, strStr3);
LOGD("copying Str3, len = %d", strLen);
pszStr3 = (char*) (*env)->GetStringUTFChars(env, strStr3, NULL);
LOGD(pszStr3);
strLen = (*env)->GetStringUTFLength(env, strStr4);
LOGD("copying Str4, len = %d", strLen);
pszStr4 = (char*) (*env)->GetStringUTFChars(env, strStr4, NULL);
LOGD(pszStr4);
LOGD("All copied");
}
JNI 函数什么都不做,它只是将传入的 java 参数复制到相应的 C 参数中,然后 returns.
调用函数这样调用它:
String temp1 = "123456";
String temp2 = "654321";
String temp3 = "lalala";
String temp4 = "hahaha";
int soPinLen = 6;
JNITest(256, soPinLen, temp1, temp2, temp3, temp4);
Java 函数声明如下:
private native void JNITest(int slotID, long pinLen, String soPin, String label, String temp1, String temp2) throws PKCS11Exception;
当我构建 JNI 文件和 运行 应用程序时,它崩溃了
strLen = (*env)->GetStringUTFLength(env, strStr1);
logcat 输出为:
E/dalvikvm( 7485): JNI ERROR (app bug): attempt to use stale global reference 0x6
E/dalvikvm( 7485): VM aborting
F/libc ( 7485): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 7485 (rust.p11example)
I/ActivityManager( 2406): Process com.example.app (pid 7485) (adj 11) has died.
如果我注释掉 strStr1 的处理并继续处理 strStr2,它会崩溃并显示以下 logcat 输出:
W/dalvikvm( 7662): JNI WARNING: received null jstring
W/dalvikvm( 7662): in
Lcom/gotrust/p11example/P11Example;.JNITest (IJLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V (GetStringUTFLength)
I/dalvikvm( 7662): "main" prio=5 tid=1 NATIVE
I/dalvikvm( 7662): | group="main" sCount=0 dsCount=0 obj=0x41b39578 self=0x41b24a68
I/dalvikvm( 7662): | sysTid=7662 nice=0 sched=0/0 cgrp=apps handle=1074798588
I/dalvikvm( 7662): | state=R schedstat=( 445394159 50687413 915 ) utm=29 stm=15 core=3
如果我评论 strStr1 和 strStr2,那么应用程序 运行 是完美的,但 LOGD 输出显示 strStr3 是“123456”,strStr4 是“654321”,这是不正确的,因为应该分配这些值改为 strStr1 和 strStr2。
此外,一旦我从 JNI 文件中删除 ulPinLen 和相应的 Java 函数调用,它就会工作 - 我在 logcat.
中得到正确的输出
为什么 JNI 参数列表中的 jint 不能超过 1 个?
谢谢。
您的参数未正确传递。
出现消息 attempt to use stale global reference 0x6
是因为您的 soPinLen
(其值为 6)正在取代字符串对象引用。 received null jstring
原因相同。
问题是您的 Java 语言声明与本机声明不匹配。错误信息中可以看到方法声明:
Lcom/gotrust/p11example/P11Example;.JNITest (IJLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
注意参数部分以 IJ
开头,表示第二个参数 (ulPinLen
) 是 64 位长。如果您修改本机或 Java 声明以匹配(即使第二个本机参数 jlong
,或将 Java 代码更改为 int
),则参数应对齐.正如您所发现的,完全删除参数也有类似的效果。
我遇到了一个非常奇怪的问题。我有一个这样定义的 JNI 函数:
void Java_com_example_app_JNITest
(
JNIEnv* env,
jobject thiz,
jint jSlotID,
jint ulPinLen,
jstring strStr1,
jstring strStr2,
jstring strStr3,
jstring strStr4
)
{
char* pszPin;
char* pszStr1;
char* pszStr2;
char* pszStr3;
char* pszStr4;
int strLen;
strLen = (*env)->GetStringUTFLength(env, strStr1);
LOGD("copying Str1, len = %d", strLen);
pszStr1 = (char*) (*env)->GetStringUTFChars(env, strStr1, NULL);
LOGD(pszStr1);
strLen = (*env)->GetStringUTFLength(env, strStr2);
LOGD("copying Str2, len = %d", strLen);
pszStr2 = (char*) (*env)->GetStringUTFChars(env, strStr2, NULL);
LOGD(pszStr2);
strLen = (*env)->GetStringUTFLength(env, strStr3);
LOGD("copying Str3, len = %d", strLen);
pszStr3 = (char*) (*env)->GetStringUTFChars(env, strStr3, NULL);
LOGD(pszStr3);
strLen = (*env)->GetStringUTFLength(env, strStr4);
LOGD("copying Str4, len = %d", strLen);
pszStr4 = (char*) (*env)->GetStringUTFChars(env, strStr4, NULL);
LOGD(pszStr4);
LOGD("All copied");
}
JNI 函数什么都不做,它只是将传入的 java 参数复制到相应的 C 参数中,然后 returns.
调用函数这样调用它:
String temp1 = "123456";
String temp2 = "654321";
String temp3 = "lalala";
String temp4 = "hahaha";
int soPinLen = 6;
JNITest(256, soPinLen, temp1, temp2, temp3, temp4);
Java 函数声明如下:
private native void JNITest(int slotID, long pinLen, String soPin, String label, String temp1, String temp2) throws PKCS11Exception;
当我构建 JNI 文件和 运行 应用程序时,它崩溃了 strLen = (*env)->GetStringUTFLength(env, strStr1);
logcat 输出为:
E/dalvikvm( 7485): JNI ERROR (app bug): attempt to use stale global reference 0x6
E/dalvikvm( 7485): VM aborting
F/libc ( 7485): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 7485 (rust.p11example)
I/ActivityManager( 2406): Process com.example.app (pid 7485) (adj 11) has died.
如果我注释掉 strStr1 的处理并继续处理 strStr2,它会崩溃并显示以下 logcat 输出:
W/dalvikvm( 7662): JNI WARNING: received null jstring
W/dalvikvm( 7662): in
Lcom/gotrust/p11example/P11Example;.JNITest (IJLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V (GetStringUTFLength)
I/dalvikvm( 7662): "main" prio=5 tid=1 NATIVE
I/dalvikvm( 7662): | group="main" sCount=0 dsCount=0 obj=0x41b39578 self=0x41b24a68
I/dalvikvm( 7662): | sysTid=7662 nice=0 sched=0/0 cgrp=apps handle=1074798588
I/dalvikvm( 7662): | state=R schedstat=( 445394159 50687413 915 ) utm=29 stm=15 core=3
如果我评论 strStr1 和 strStr2,那么应用程序 运行 是完美的,但 LOGD 输出显示 strStr3 是“123456”,strStr4 是“654321”,这是不正确的,因为应该分配这些值改为 strStr1 和 strStr2。
此外,一旦我从 JNI 文件中删除 ulPinLen 和相应的 Java 函数调用,它就会工作 - 我在 logcat.
中得到正确的输出为什么 JNI 参数列表中的 jint 不能超过 1 个?
谢谢。
您的参数未正确传递。
出现消息 attempt to use stale global reference 0x6
是因为您的 soPinLen
(其值为 6)正在取代字符串对象引用。 received null jstring
原因相同。
问题是您的 Java 语言声明与本机声明不匹配。错误信息中可以看到方法声明:
Lcom/gotrust/p11example/P11Example;.JNITest (IJLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
注意参数部分以 IJ
开头,表示第二个参数 (ulPinLen
) 是 64 位长。如果您修改本机或 Java 声明以匹配(即使第二个本机参数 jlong
,或将 Java 代码更改为 int
),则参数应对齐.正如您所发现的,完全删除参数也有类似的效果。