android - GetByteArrayRegion 导致 ArrayIndexOutOfBoundsException

标签 android memory-leaks android-ndk speex

我正在尝试使用 Speex 库解码 Speex 编码的音频文件,但我总是得到 ArrayIndexOutOfBoundsException

JNIEXPORT jint JNICALL Java_com_app_shared_Speex_decode
    (JNIEnv *env, jobject obj, jbyteArray encoded, jshortArray lin, jint size) {

        jbyte buffer[dec_frame_size ];
        jshort output_buffer[dec_frame_size ];
        jsize encoded_length = size;

        if (!codec_open)
            return 0;

        env->GetByteArrayRegion(encoded, rtp_header, encoded_length, buffer);

        /*  
        jboolean isCopy;
        jbyte* data = env->GetByteArrayElements(encoded, &isCopy);
        if(isCopy){
        memcpy(buffer, data, encoded_length);               
        env->ReleaseByteArrayElements(encoded, data, JNI_ABORT);
        }
        */

        speex_bits_read_from(&dbits, (char *)buffer, encoded_length);
        speex_decode_int(dec_state, &dbits, output_buffer);

        std::string bufStr;

        for(int i=0; i<20; i++){
            char buff[100];
            sprintf(buff, "Speex test %d => %d", i, output_buffer[i]);
            bufStr = buff;
            LOGI(bufStr.c_str());
        }

        bufStr = "before SetShortArrayRegion";
        LOGI(bufStr.c_str());

        (env)->SetShortArrayRegion(lin, rtp_header, dec_frame_size, output_buffer);

        bufStr = "after SetShortArrayRegion";
        LOGI(bufStr.c_str());

        return (jint)dec_frame_size;            
}

我得到:

SharedSpeex before SetShortArrayRegion
dalvikvm    JNI WARNING: JNI method called with exception pending
dalvikvm              in Lcom/company/shared/Speex;.decode:([B[SI)I (SetShortArrayRegion)
dalvikvm    Pending exception is:
dalvikvm    java.lang.ArrayIndexOutOfBoundsException: [B offset=12 length=1634 src.length=1634

有趣的是,如果我完全注释包含 SetShortArrayRegion 的行,则在退出范围时会发生异常:

SharedSpeex       before SetShortArrayRegion
SharedSpeex       after SetShortArrayRegion
AndroidRuntime    Shutting down VM
dalvikvm          threadid=1: thread exiting with uncaught exception (group=0xa62ca288)
AndroidRuntime    FATAL EXCEPTION: main
AndroidRuntime    java.lang.ArrayIndexOutOfBoundsException: [B offset=12 length=1634 src.length=1634

在官方JNI文档显然更喜欢 GetByteArrayRegion 而不是 GetByteArrayElements 因为:

  • 降低了程序员出错的风险——没有在出现问题后忘记调用 Release 的风险。

最佳答案

GetByteArrayRegion 检查数组的边界以确保您没有超出末尾。 GetByteArrayElements 只是获取指向数组开头的指针,因此您的 memcpy() 可以在不被注意的情况下自由运行到结尾。

异常中注明了超限的原因:

[B offset=12 length=1634 src.length=1634

[B 表示 byte[]。数组的长度与请求的长度 (1634) 相匹配,但它是从数组中的偏移量 12 字节开始的。因此,您正在尝试读取末尾后的 12 个字节。

Java 代码抛出的异常不会中断您的 C 代码; VM 只是在当前线程上设置一个标志。您必须使用 ExceptionCheck 显式测试它们,然后清除它们或返回到 VM 将继续抛出过程的 Java 代码。如果您启用了 CheckJNI,并且 VM 看到您进行了少数调用并引发了异常,您将收到“JNI 警告”并且 VM 中止。

关于android - GetByteArrayRegion 导致 ArrayIndexOutOfBoundsException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19881355/

相关文章:

memory-leaks - 为什么启用 Firebug 会发生内存泄漏?

mysql - 与其他 DBMS 相比,MySQL 是否消耗更多资源?

android - 在使用 CMake (CMakeLists.txt) 而不是 ndk-build (Android.mk) 的 android ndk 项目中包含 GStreamer

android - 如何在另一个 View 下添加动态按钮?

java - 如何从内部存储中读取对象?

android - 如何在没有成员标签的情况下将 JsonElement 转换为 Json?

android - 将 stagefright 和 NuPlayer 反向移植到 Android 2.2

android - Google APIs Intel x86 Atom System Image (Android Studio) 的未知错误

android - Fragment 中的 Asynctask 生命周期

android - 如何在不发疯的情况下使用 ARM DS-5 在 eclipse 中调试 Android native 库?