Android NDK抛出信号sigsegv:调试模式下的无效地址

时间:2018-05-21 15:41:48

标签: android android-ndk

我最近实现了android NDK来隐藏我的应用密钥和秘密。因为每当我在android studio中以调试模式运行我的应用程序时,我都会这样做,我的断点会被sigsegv中断(信号sigsegv:无效地址(错误地址:0x8))。当我的任何进程完全访问NDK时会发生这种情况。我对NDK的新手感到困惑,我感到很困惑。我的C代码非常简单,看起来像:

#include <jni.h>

JNIEXPORT jstring JNICALL
Java_com_my_company_co_utilities_UtilFuncs_getSecretOne(JNIEnv *env, jobject instance) {
    return (*env)->  NewStringUTF(env, "my_secret_1");
}
JNIEXPORT jstring JNICALL
Java_com_my_company_co_utilities_UtilFuncs_getSecretTwo(JNIEnv *env, jobject instance) {
    return (*env)->  NewStringUTF(env, "my_secret_2");
}
JNIEXPORT jstring JNICALL
JJava_com_my_company_co_utilities_UtilFuncs_getKeyOne(JNIEnv *env, jobject instance) {
    return (*env)->  NewStringUTF(env, "my_key_1");
}

JNIEXPORT jstring JNICALL
Java_com_my_company_co_utilities_UtilFuncs_getKeyTwo(JNIEnv *env, jobject instance) {

    return (*env)->NewStringUTF(env, "my_key_2");
}

我在我的静态UtilFuncs类中访问它,如:

static {
        System.loadLibrary("keys");
    }

    public static native String getSecretOne();

    public static String getSecret() {
            return getSecretOne();

    }

当我正常运行应用程序时,它运行得很好,但由于这些sigsegv,它使调试无法使用:当我试图读取监视变量时,无效地址错误即将出现。任何人以前遇到过这个或者知道我做错了什么?

更新:更新到Android 9的手机上没有抛出错误,所以我的问题已经解决,但我仍然不知道是什么原因导致了它。对原始原因的任何理论仍然感兴趣。

5 个答案:

答案 0 :(得分:1)

这是我要通过过去的JNI崩溃创建的一小部分要检查的内容。

  • 你正在使用C本机代码吗?不是C ++?检查一切是否一致。文件扩展名应为.c,如果有的话,请检查声明文件。 Android NDK documentation的“JNI提示”中有一小部分(JavaVM和JNIEnv部分)。
  • 您是否确定使用NewStringUTF的方式,使用字符串作为参数?请查看相同Android NDK documentation
  • 的“UTF-8和UTF-16字符串”部分
  • 在您的情况下,故障地址是一个低值。检查Android documentation on native crash的“诊断本机崩溃”一章中的“低地址空指针取消引用”部分。
  • 您是否尝试过全部使用C ++?我正在使用类似的功能,如果您想尝试:

myNativeLib.cpp

extern "C"
JNIEXPORT jstring
JNICALL Java_com_my_company_co_utilities_UtilFuncs_getSecretOne(
    JNIEnv *env
    ,jobject /* this */
    )
{
    unsigned char my_secret_1[] = {0x1a, 0xb2, 0xb7, 0x39, 0x00, 0x20, 0xb1, 0x0a, 0x33}; 
    return env->NewStringUTF(my_secret_1);
}

答案 1 :(得分:1)

当我遇到相同的线程时,我发现了该线程:添加NDK代码后,在Android Studio(v3.2.1)调试器中运行我的应用程序时出现SIGSEGV错误。在没有调试器的情况下运行它可以正常执行。

我没有找到解决方案,但是我找到了进一步的线索。

在调试器捕获到SIGSEGV故障之后,打开“断点”对话框。 enter image description here

这在'libart.so:art_sigsegv_fault'中显示了一个活动断点:

enter image description here

libart中似乎有一些sigsegv故障的历史。我没有找到任何解决方案。但是,禁用此断点确实允许我继续调试应用程序(一种变通方法)。

答案 2 :(得分:0)

这不是解决方案!

我认为您应该坚持使用@NoonanRosenblum解决方案,并尝试在NDK中找到其真正原因并加以解决。

但是如果您没有时间,可以在模块gradle构建文件中注释掉对CMake的调用:

buildTypes {
...
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}


    buildTypes {
    ...
//        externalNativeBuild {
//            cmake {
//                path "src/main/cpp/CMakeLists.txt"
//            }
    }
    }

不要忘记,如果您调用本机方法,它将崩溃,因此,仅当您要逐步调试并且不想跳过烦人的本机崩溃断点时,才使用它。

答案 3 :(得分:0)

如果您确定C代码始终可以正常工作,也许您想忽略这样的错误并在Java中进行调试。 将“调试配置”-“调试类型”从任何更改为“仅Java”

guide

答案 4 :(得分:0)

万一其他人最近遇到这种情况(2020年10月Android Studio 4.0.1 NDK 19.2.5345600):

在相似的情况下,只有在将参数传递给本机方法(例如jstring)且仅在x86仿真器上时,我才会遇到相同的崩溃。

例如,x86 API 30仿真器上的以下代码一旦遇到断点,便会崩溃,但可以正常运行:

extern "C" JNIEXPORT jstring JNICALL
Java_some_package_SomeClass_someMethod(
        JNIEnv* env,
        jobject /* this */,
        jstring foo) {
    
    // anything ...
}

但是,我可以在x86_64仿真器或物理设备上使用断点调试此代码,而不会出现问题。因此,解决方案是使用x86_64 AVD或始终在设备上调试。