【问题标题】:Android C++: uncaught exception from loaded shared libraryAndroid C++:加载的共享库中未捕获的异常
【发布时间】:2019-04-17 05:56:52
【问题描述】:

我是 stackoverflow 的新手,我想寻求有关 Android C++ 的帮助。

我正在尝试用 C++ 实现一个非常简单的 Android 测试程序,它调用一个加载的共享库中的一个函数,该库也是用 C++ 实现的。

这是我的主要 JNI 实现 (native-lib.cpp):

#include <jni.h>
#include <string>
#include <dlfcn.h>
#include "external.hpp"

extern "C" JNIEXPORT jstring JNICALL
Java_com_useless_myapplication_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    void* handle;
    void (*funcext)();
    handle = dlopen("libexternal.so",RTLD_LAZY);
    funcext = (void (*)(void))dlsym(handle, "_Z5func2v");
    try {
        funcext();
    }
    catch (MyException &err)
    {
        std::string hello = "MyException from C++";
        return env->NewStringUTF(hello.c_str());
    }
    catch (GenericException &err)
    {
        std::string hello = "GenericException from C++";
        return env->NewStringUTF(hello.c_str());
    }
    catch (GenericException* err)
    {
        std::string hello = "GenericException* from C++";
        return env->NewStringUTF(hello.c_str());
    }

    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

这是我的libexternal.so 实现(external.cpp):

#include <jni.h>
#include <string.h>
#include "external.hpp"
GenericException::GenericException(){};
GenericException::GenericException(int errcode,char* msg)
{
        errorcode = errcode;
        memset(message,0,256);
        strcpy(message,msg);
}

MyException::MyException(int errcode,char* msg)
{
    errorcode = errcode;
    memset(message,0,256);
    strcpy(message,msg);
}

void func()
{
    throw MyException(10,"Error1!");
}
bool func3()
{
    try {
        func();
    }
    catch (GenericException &err)
    {
        return false;
    }
    return true;
}

void func2()
{
    if (!func3())
        throw MyException(11,"Error2!");
}

external.hpp文件定义如下:

void func();
void func2();
bool func3();
class GenericException
{
    public:
    GenericException();
    GenericException(int errcode,char* msg);
    protected:
    int errorcode;
    char message[256];
};

class MyException : public GenericException
{
    public:
    MyException(int errcode,char* msg);
};

程序编译并链接干净,但是当我运行它时,我的 android 应用程序崩溃并在 logcat 中显示以下消息:

2018-11-14 09:57:42.058 6519-6519/com.useless.myapplication A/libc: /usr/local/google/buildbot/src/android/ndk-release-r18/external/libcxx/../../external/libcxxabi/src/abort_message.cpp:73: abort_message: assertion "terminating with uncaught exception of type MyException" failed

当我尝试执行external.cpp line 41 时出现错误:

throw MyException(11,"Error2!");

根据其他帖子的建议,我发现我已尝试在我的应用程序 build.gradle cppflgs 中启用 -frtti 标志,但这并没有解决错误。

我尝试在 LinuxMacOS 上运行相同的代码(实际上没有 Java 顶层),但在这些平台上,@987654333 捕获了异常@代码。

关于 Android 中的 C++ 异常,有什么我不知道的吗? 我如何能够捕获我在 Android 上使用 dlopen 加载的库引发的异常?

谢谢

【问题讨论】:

  • 您的GenericException 类不是从std::exception 派生的有什么特殊原因吗?
  • 事实上,我正在将一个多平台 C++ 专有项目移植到 Android 上。由于我无权展示我编写此示例的代码以与我正在移植的原始项目保持一致:由于原始项目异常不是从std::exception 派生的,我决定也不派生我的示例的异常。

标签: android c++ android-ndk shared-libraries dlopen


【解决方案1】:

你的异常类型没有关键函数,所以它的 typeinfo 是用vague linkage 发出的。这意味着它在每个使用它的库中都是一个弱符号。

您的 JNI 库加载并解析它自己的类型信息。然后加载您的 dlended 库并解析其自己的类型信息,因为它无法访问父范围(System.loadLibrary 使用 RTLD_LOCAL)。因此,您的异常类型有两个单独的 typeinfo 对象。通过比较 typeinfo 对象的地址来检查 RTTI 是否相等(参见C++ ABI spec)。

如果不直接将您的 JNI 代码链接到 libexternal.so,我不确定是否可以解决此问题。如果您添加了使这项工作所需的关键函数(将在 libexternal.so 中定义),那么我相信您需要链接到它才能链接您的 JNI 代码。

【讨论】:

  • 非常感谢丹的回答。你是对的,如果我在我的类中插入一个关键函数,我需要与libexternal.so 链接以获得正确链接的native-lib.so:当然,如果我将native-liblibexternal 链接,Android 示例运行正确。同时,我还尝试通过将 java 包装器放在顶部并通过 JNI 调用来在 Linux 下实现所描述的行为:不幸的是,这似乎是 Android 唯一的行为,因为在 Linux 上,即使一切都运行,异常也会被正确捕获Java 包装器。
  • 如果是这种情况,那么您的系统不符合 C++ ABI。大概您在系统上使用 GNU 的 libstdc++,它为 RTTI 比较执行名称字符串相等性检查。这可能导致两个完全不相关但名称相同的类型被视为相等,这就是规范不使用此方法的原因。
猜你喜欢
  • 2015-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多