线程中的SetDoubleArrayRegion上的JNI SIGSEGV

时间:2018-04-17 11:13:03

标签: java android java-native-interface sigsegv

我试图在一个单独的线程中从Java调用以下函数:

extern "C" JNIEXPORT jdoubleArray

JNICALL
Java_de_bastian_sip2labor_MainActivity_filtertest(JNIEnv *env, jobject, jdoubleArray ka)
{
  double b_y1[121];
  int k;
  int j;
  static const double dv0[12] = { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.65 };

  jdouble *sig1;
  sig1=env->GetDoubleArrayElements(ka, 0);


  memset(&b_y1[0], 0, 121U * sizeof(double));
  for (k = 0; k < 12; k++) {
    for (j = k; j + 1 < 122; j++) {
     b_y1[j] += dv0[k] * sig1[j - k];
    }
  }

  env->ReleaseDoubleArrayElements(ka,sig1,JNI_ABORT);

  jdoubleArray output = env->NewDoubleArray( sizeof(b_y1) );
  env->SetDoubleArrayRegion( output, 0, sizeof(b_y1), &b_y1[0] );

  return output;
}

它是一个过滤器,它接受一个双精度数组,修改它,并将其作为函数结果返回给java。

应用程序在启动时崩溃,我假设因为这一行:

env->SetDoubleArrayRegion( output, 0, sizeof(b_y1), &b_y1[0] );

第一次遇到这个问题时,在调用onPause()之后发生了这个问题,而带调用的单独线程可能仍在运行。因此我认为它与生命周期有关。是否有可能在尝试执行SetDoubleArrayRegion()之前以某种方式检查活动是否仍处于活动状态,还是可能是另一个问题?

奇怪的是,代码工作正常,直到最近: 我开始读取一个文件,然后将其用作过滤器的输入。在全新安装后第一次启动应用程序时,它会要求用户授予文件读取权限。如果用户授予他们应用程序正常工作,你可以看到过滤器输出。从那时起,当应用程序启动时,已经授予了读取文件的权限,应用程序尝试立即启动过滤器,然后崩溃。

简单的logcat输出:

A/libc: Fatal signal 11 (SIGSEGV), code 2, fault addr 0x89fa2830 in tid 8498 (Thread-5)

详细的Logcat输出:

#00 pc 0001a21e  /system/lib/libc.so (memcpy+46)
    #01 pc 004394a6  /system/lib/libart.so (_ZN3art3JNI23SetPrimitiveArrayRegionIP13_jdoubleArraydNS_6mirror14PrimitiveArrayIdEEEEvP7_JNIEnvT_iiPKT0_+1174)
    #02 pc 0041e87c  /system/lib/libart.so (_ZN3art3JNI20SetDoubleArrayRegionEP7_JNIEnvP13_jdoubleArrayiiPKd+44)
    #03 pc 0015c9d2  /system/lib/libart.so (_ZN3art8CheckJNI23SetPrimitiveArrayRegionEPKcNS_9Primitive4TypeEP7_JNIEnvP7_jarrayiiPKv+1474)
    #04 pc 00144665  /system/lib/libart.so (_ZN3art8CheckJNI20SetDoubleArrayRegionEP7_JNIEnvP13_jdoubleArrayiiPKd+53)
    #05 pc 00000e10  /data/app/de.bastian.sip2labor-FUb-fvR-Nwyxco0g-cmxow==/lib/x86/libsip2labor-lib.so (_ZN7_JNIEnv20SetDoubleArrayRegionEP13_jdoubleArrayiiPKd+160)
    #06 pc 00000fcc  /data/app/de.bastian.sip2labor-FUb-fvR-Nwyxco0g-cmxow==/lib/x86/libsip2labor-lib.so (Java_de_bastian_sip2labor_MainActivity_filtertest+428)
    #07 pc 0063ec67  /system/lib/libart.so (art_quick_generic_jni_trampoline+71)
    #08 pc 000049d3  /dev/ashmem/dalvik-jit-code-cache (deleted)

我在这里做错了什么?提前感谢您的努力。

1 个答案:

答案 0 :(得分:1)

在拨打b_y1时,您正在阅读env->SetDoubleArrayRegion( output, 0, sizeof(b_y1), &b_y1[0] );数组的末尾

sizeof(b_y1)

以字节为单位返回数组的大小,不是元素的数量。在我的平台上,这是968,但是你的b_y1只有121个元素,所以这是未定义的行为。

您可以通过传递121(数组的实际大小)而不是sizeof(b_y1)来解决此问题。但是既然你正在使用C ++,我建议切换到使用std::array,因为它保持了你的大小,并且通常有一个更高级别的api:

std::array<double, 121> b_y1;
int k;
int j;
static const double dv0[12] = { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.65 };

jdouble *sig1;
sig1 = env->GetDoubleArrayElements(ka, 0);

b_y1.fill(0);
for (k = 0; k < 12; k++) {
    for (j = k; j + 1 < 122; j++) {
        b_y1[j] += dv0[k] * sig1[j - k];
    }
}

env->ReleaseDoubleArrayElements(ka, sig1, JNI_ABORT);

jdoubleArray output = env->NewDoubleArray(b_y1.size());
env->SetDoubleArrayRegion(output, 0, b_y1.size(), b_y1.data());

return output;