【问题标题】:Android NDK throwing signal sigsegv: invalid address in debug modeAndroid NDK 抛出信号 sigsegv:调试模式下的无效地址
【发布时间】:2018-05-21 15:41:47
【问题描述】:

我最近实现了 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: invalid address 错误出现在我尝试读取监视变量时,它使调试完全无法使用。有人遇到过这种情况或知道我做错了什么吗?

更新:更新到 Android 9 的手机不会出现该错误,因此我的问题已解决,但我仍然不知道是什么原因造成的。仍然会对有关原始原因的任何理论感兴趣。

【问题讨论】:

  • 这可能与你的崩溃没有任何关系,但是你所有的 C 函数签名都是不正确的:因为你已经在你的 Java 代码中声明了它们static,它们实际上收到了一个@ 987654324@ 作为他们的第二个参数,而不是 jobject
  • 谢谢,我更改了它,但不幸的是在调试模式下仍然出现错误。这真的让我很困惑,因为这些方法显然是有效的,但是任何时候在调试中调用它都会抛出它并中断我在调试中看到的任何内容。
  • 我以前遇到过这个。我通过使 Android Studio 中的缓存无效并确保所有 Android SDK 工具都是最新的,以某种方式修复了它。我还通过在执行触发断点的操作之前附加调试器来避免它。
  • 好建议,但遗憾的是没有解决我的问题?你能想到你还做了什么来修复它吗?
  • 您可以使用 ndk-stack 准确找出导致分段错误的变量。

标签: android android-ndk


【解决方案1】:

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

我还没有找到解决办法,但是我找到了进一步的线索。

调试器捕获 SIGSEGV 故障后,打开断点对话框。

这显示了“libart.so: art_sigsegv_fault”处的活动断点:

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

【讨论】:

  • 感谢您的提醒,我很感激。不幸的是,这对我不起作用。我仍然在关闭该断点的情况下获得 SIGSEGV。我什至在静音断点后仍然得到它,这没有任何意义。如果您找到解决问题的方法,请告诉我,如果它可以帮助我。
  • item 'Symbolic Breakpoints' 每次我开始调试时都会重新出现,即使我取消选中它 - 错误仍然会出现在本机代码中的烦人断点,我需要跳过(超过 30 次)然后该过程继续进行。
【解决方案2】:

如果其他人最近遇到这种情况(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 或始终在设备上调试。

【讨论】:

    【解决方案3】:

    如果你确定你的 C 代码总是能正常工作,也许你想忽略这样的错误并在 java 中调试。 将“调试配置”-“调试类型”从任何更改为“仅限 Java”

    guide

    【讨论】:

      【解决方案4】:

      这是我在过去必须解决的 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);
      }
      

      【讨论】:

      • 谢谢,我试试看。
      • 要将其更改为 C++,除了将其扩展名更改为文件上的 .cpp 以及在 Android.mk 文件中提到的位置之外,我是否需要在 .c 文件之外执行任何操作? gradle有什么需要改变的吗?
      • 仍然发生在 c++ 中。由于类型不匹配,我确实必须将 unsigned char 更改为 const char。还有像这样将字符串转换为单个字符的十六进制数组的好方法吗?
      • 好吧,它没有解决它,但它是一个很好的答案,没有其他人回答。所以我要奖励赏金。如果您还有其他想法,请告诉我。
      • 好的,谢谢。我通常只使用在线转换器字符串到十六进制。我现在无法使用我的工具,但下周会深入研究一下这个主题,看看我是否能找到方法。 JNI SIGSGEV 可能是一场噩梦!
      【解决方案5】:

      这不是解决办法!

      我认为你应该坚持使用@NoonanRosenblum asnwer 并尝试在你的 NDK 中找到它的真正原因并修复它。

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

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

      不要忘记,如果你调用原生方法会崩溃,所以只有在你想逐步调试并且不想跳过烦人的原生崩溃断点时才使用它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-04
        • 2013-07-02
        • 2019-01-16
        • 2011-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-30
        相关资源
        最近更新 更多