JNI Linux分段故障 [英] JNI Linux segmentation fault

查看:216
本文介绍了JNI Linux分段故障的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的JNI库在Windows上可以完美运行,但是在Linux上,我总是遇到奇怪的分段错误.

My JNI library works flawlessly on Windows, however, on Linux I always get a strange segmentation fault.

siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0x0000000000000000

崩溃文件中的堆栈尾部是这样的:

The stack crace from the crash file is this:

C  [libfmodjavaL.so+0xfb8c]  JNIEnv_::GetStaticObjectField(_jclass*, _jfieldID*)+0x18
C  [libfmodjavaL.so+0xf72b]  Logger::sendToSystemOut(bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)+0x75
C  [libfmodjavaL.so+0xf7c2]  Logger::log(char const*)+0x4c
C  [libfmodjavaL.so+0xd70d]  fmodDebugCallback(unsigned int, char const*, int, char const*, char const*)+0x127

因此,在调用Logger类中的GetStaticObject字段时,它似乎崩溃了.这就是这种方法:

So it appears that it crashed when calling GetStaticObject field in the Logger class. This is that method:

void Logger::sendToSystemOut(bool error, std::string message) {
    JNIEnv* jni = FMODWrapper::utils->getJNI();

    jobject printStream;
    if (error) {
        printStream = jni->GetStaticObjectField(this->systemClass, this->errFieldID);
    } else {
        printStream = jni->GetStaticObjectField(this->systemClass, this->outFieldID);
    }

    jobject messageString = jni->NewStringUTF(message.c_str());
    jni->CallObjectMethod(printStream, this->printlnMethodID, messageString);
}

因此,我猜测有关存储这些字段的类和字段ID的某些事情是不正确的.但是,很奇怪的是,我的库启动时,即使从FMOD调用fmodDebugCallback时,我也得到了日志输出.

So I'm guessing something's not right about storing the class and field IDs of these fields. But the weird thing is, I get logging output when my library starts up, even from FMOD, which the fmodDebugCallback gets called by.

Logger::Logger(const char* name) {
    this->name = name;

    JNIEnv* jni = FMODWrapper::utils->getJNI();

    this->systemClass = FMODWrapper::utils->findClass("java/lang/System");
    this->outFieldID = jni->GetStaticFieldID(this->systemClass, "out", "Ljava/io/PrintStream;");
    this->errFieldID = jni->GetStaticFieldID(this->systemClass, "err", "Ljava/io/PrintStream;");

    jclass printStreamClass = FMODWrapper::utils->findClass("java/io/PrintStream");
    this->printlnMethodID = jni->GetMethodID(printStreamClass, "println", "(Ljava/lang/String;)V");
}

因此,日志记录在Windows上可以完美运行,但是一段时间后在Linux上崩溃.在Fedora 29 64位上与g ++一起编译.

So, logging works flawlessly on Windows, but after some time crashes on Linux. Compiled with g++ on Fedora 29 64-bit.

更新:我获取JNIEnv *的方法

Update: my method for getting a JNIEnv*

JNIEnv* Utils::getJNI() {
    JNIEnv* jni;

    int getEnvResult = FMODWrapper::jvm->GetEnv((void**) &jni, JNI_VERSION_1_6);

    if (getEnvResult == JNI_EDETACHED) {
        FMODWrapper::jvm->AttachCurrentThread(ANDROID_VOIDPP_CAST &jni, nullptr);
    }

    return jni;
}

更新2:由于我收到日志消息,因此代码本身可以工作到一定程度.可能与线程有关? https://hastebin.com/kuzefuwawu.txt

Update 2: the code itself works up to a certain point since I'm getting log messages. Might be something to do with threads? https://hastebin.com/kuzefuwawu.txt

推荐答案

systemClass,errFieldId和outFieldID都是从不同的JNIEnv获得的.

systemClass, errFieldId, and outFieldID are all obtained from a different JNIEnv.

无法缓存JNIEnv: 保持对JNIEnv环境的全局引用

The JNIEnv cannot be cached: Keeping a global reference to the JNIEnv environment

就像它不能被缓存一样,您不能存储从另一个JNIEnv获得的ID,这些ID您将不再使用,也不应使用它产生的任何东西.您需要从当前有效的JNIEnv中获取所有内容.

Just as it cannot be cached, you cannot store ids that were obtained from the other JNIEnv that you should no longer be using, nor should you be using anything that came from it. You need to get them all from the current valid JNIEnv.

这篇关于JNI Linux分段故障的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆