如果还有超过 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),则参数应对齐.正如您所发现的,完全删除参数也有类似的效果。