【问题标题】:Fatal signal 11 (SIGSEGV)致命信号 11 (SIGSEGV)
【发布时间】:2013-01-10 17:46:05
【问题描述】:

我有一个奇怪的错误,我找不到它的来源。 logcat 中出现的唯一内容是:

01-10 17:07:10.665: A/libc(20449): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)

当我运行我的应用程序时,我没有立即收到此错误,而是在随机时间(1 分钟到 5 分钟之间)后收到此错误。我无法重现此错误,它似乎是随机的,并且由于没有其他信息,因此很难调试。我尝试将一些日志信息添加到我的库中,但我仍然无法说出崩溃发生的位置。

我运行同一个应用程序 x 次,我得到了不同的 SIGSEGV 地址(有时它与以前的地址相同:

01-10 17:29:04.650: A/libc(21588): Fatal signal 11 (SIGSEGV) at 0x6c707063 (code=1)

01-10 17:25:55.165: A/libc(21473): Fatal signal 11 (SIGSEGV) at 0x0069004c (code=1)

01-10 17:11:58.780: A/libc(20742): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)

01-10 17:00:02.010: A/libc(20160): Fatal signal 11 (SIGSEGV) at 0x00000018 (code=1)

我的应用正在使用一个 C++ 库,该库具有一个从服务器接收更新的 NetworkThread。在 Java 端,有一个 WorkerThread 检查是否有来自 NetworkThread 的新更新,如果有新更新,它会通知所有侦听器。我还有一个 LocationSpotter(在 Java 端),它会在位置更新时进行一些 JNI 调用。

有没有办法调试这个或使用我从 SIGSEGV 获得的地址来调试应用程序?此外,我正在使用共享 JavaVM 对象来检索当前的 JNIEnv(并调用 AttachCurrentThread)。那个线程安全吗?

我注意到在收到 SIGSEGV 错误后(在应用程序实际崩溃之前),我仍然收到来自 NetworkThread 的更新。这意味着 NetworkThread 可能正在工作。

我还注意到一行可能是我的问题的根源(在 notifyAll 方法中),因为在 SIGSEGV 之前打印的最后一条消息是“notifyAll1”:

for (unsigned i = 0; i < listeners.size(); i++) {
    try {
        __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll1");
        if (listeners.at(i) == NULL)
            __android_log_print(ANDROID_LOG_INFO, "FROM C++", "LISTENER NULL");


        listeners.at(i)->update(u); // <- This line is a potential suspect
        __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll2");

日志猫:

01-10 17:07:10.665: I/FROM C++(20449): notifyAll1
01-10 17:07:10.665: A/libc(20449): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)

然后我尝试在每个侦听器的 update 方法的第一行打印一个日志,但没有一个被打印(我认为这真的很奇怪)。

任何帮助将不胜感激

【问题讨论】:

  • 如果您的崩溃后创建了相关的墓碑文件,您能否从 /data/tombstones 目录添加相关的墓碑文件?
  • 我找不到墓碑文件。我试图进入 DDMS 透视图 -> 文件资源管理器 -> 数据 -> 数据 ->(您的包)-> 文件 ->(您的文件)但什么也没有……我也在手机上尝试过,但没有更多结果
  • 对了,你知道为什么我手机的数据目录下什么都没有吗?我应该让我的手机能够读取墓碑文件吗? (stackoverflow.com/a/8921133/1304830)
  • 从根本上说,您取消引用了一个无效指针,可能是在您的代码中通过将一个指针交给系统库代码,或者不太可能触发平台错误。您要查找的主要内容是崩溃的本机堆栈转储,是否已经在您的 logcat 中?在受保护的设备上无法访问顶级 /data 目录,但您可以从 adb shell cd 到下面的特定目录。或者您可以在 adb shell 已经是 root 的模拟器上复制问题。
  • 您是如何在本机代码中启用异常的?您使用哪种 STL?

标签: android android-ndk java-native-interface


【解决方案1】:

当您尝试访问当时未创建的任何对象时,通常会发生致命信号错误。所以请正确检查它们。

【讨论】:

    【解决方案2】:

    我认为您应该像这样重写 notifyAll 循环:

    for (unsigned i = 0; i < listeners.size(); i++) {
      try {
        __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll1 i=%u", i);
        auto listener = *listeners.at(i);
    
        if (&listener == NULL) {
          __android_log_print(ANDROID_LOG_INFO, "FROM C++", "LISTENER NULL");
        }
        else {
          __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll2 : listener[%u] at %p", i, &listener);
          listener.update(u);
        }
    
    • 在您的原始代码中,检查仅打印到日志,但 update() 仍然会失败(@Robin 注意到这一点)
    • 在您的原始代码中,listener 可能会在 check 和 update() 之间获得无效的 NULL
    • 即使经过上述更改,如果 listeners.at(i) 指向的侦听器对象无效,update() 也可能崩溃。

    但有可能因为异常处理而发生崩溃。你没有透露 catch(...) 代码,所以我不能谈论这个。

    【讨论】:

      【解决方案3】:

      好像很明显

      if (listeners.at(i) == NULL)
                  __android_log_print(ANDROID_LOG_INFO, "FROM C++", "LISTENER NULL");
      
      
              listeners.at(i)->update(u); // <- This line is a potential suspect
              __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll2");
      

      应该是

      if (listeners.at(i) == NULL) {
          __android_log_print(ANDROID_LOG_INFO, "FROM C++", "LISTENER NULL");
      } else {
          listeners.at(i)->update(u); // <- This line is a potential suspect
          __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll2");
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多