使用 JNA 使用本机 fortran 库时查找 SIGSEGV 原因的问题

Posted

技术标签:

【中文标题】使用 JNA 使用本机 fortran 库时查找 SIGSEGV 原因的问题【英文标题】:Problems finding the cause of SIGSEGV while using a native fortran library using JNA 【发布时间】:2017-01-20 14:39:21 【问题描述】:

我正在使用 JNA 与来自 Java/Scala 的本机 Fortran 库(物理)交互,使用 Apache Spark 分布式计算框架调用。

以下报告是使用我的库/opt/MYORG/hdd/usr/local/lib/mylib.so 生成的,该库使用ifort 和调试编译器选项编译

-shared -fPIC -save -g -check all -fpe0 -traceback -static -static-intel -Bstatic

由于SIGSEGV,我的执行程序不时崩溃,JVM 错误报告表明:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fea0f490700, pid=33080, tid=140647778658048
#
# JRE version: Java(TM) SE Runtime Environment (8.0_60-b27) (build 1.8.0_60-b27)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.60-b23 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  0x00007fea0f490700

完整的报告在这里上传:https://www.amazon.com/clouddrive/share/GDqXyIRNVkY86XYCXkorjiuE4bZm4AmnNWllXBhMVmk?encoding=UTF8&mgh=1&ref=cd_ph_share_link_copy

我设法创建了一个核心转储,我用

对其进行了分析
gdb /usr/java/jdk1.8.0_60/bin/java core.33080

(gdb) bt
#0  0x00007fed0a04f1d7 in raise () from /usr/lib64/libc.so.6
#1  0x00007fed0a0508c8 in abort () from /usr/lib64/libc.so.6
#2  0x00007fed0995b6b5 in os::abort(bool) () from /usr/java/jdk1.8.0_60/jre/lib/amd64/server/libjvm.so
#3  0x00007fed09af9bf3 in VMError::report_and_die() () from /usr/java/jdk1.8.0_60/jre/lib/amd64/server/libjvm.so
#4  0x00007fed09960edf in JVM_handle_linux_signal () from /usr/java/jdk1.8.0_60/jre/lib/amd64/server/libjvm.so
#5  0x00007fed09957673 in signalHandler(int, siginfo*, void*) () from /usr/java/jdk1.8.0_60/jre/lib/amd64/server/libjvm.so
#6  <signal handler called>
#7  0x00007fea0f490700 in ?? ()
#8  0x00007fed0a7fcbc2 in __nptl_deallocate_tsd () from /usr/lib64/libpthread.so.0
#9  0x00007fed0a7fcdd3 in start_thread () from /usr/lib64/libpthread.so.0
#10 0x00007fed0a11173d in clone () from /usr/lib64/libc.so.6

我用

进一步分析了核心
thread apply all bt full

(输出可以在这里找到:https://www.amazon.com/clouddrive/share/ZUmv6GEM2oJ0MCCqfnNEs2OOateJVGnhnxoHsJnbvBV?ref_=cd_ph_share_link_copy)

但我没有看到当前在我自己的(可能有故障的)库mylib.so 中的任何线程,所有线程似乎都在等待。到目前为止,我没有指出 mylib.so 导致 SIGSEGV 的事实,但是如果我在代码中用 Mock 替换对 mylib.so 的调用(即没有实际的本机调用),则不会出现 SIGSEGV,因此我的结论是问题一定出在对我的本地库的 JNA 调用中。

到目前为止,我尝试了以下提示:https://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors 没有成功

有人可以帮我找出上述SIGSEGV的原因吗?

【问题讨论】:

可能不想要-dynamic-static(你应该放弃后者,但这有时会因平台而异)。 @technomage 我在哪里使用-dynamic 我担心你的 Fortran 库几乎可以有任何东西。你确定它没有错误吗? FWIW 您的错误报告表明错误线程试图执行数据 - 指令指针 (RIP) 没有引用代码页。这可能是由于堆栈损坏 - 堆栈上的返回指令指针,在过程结束时引用,已被丢弃。堆栈和基指针 (RSP/RBP) 的不一致以及缺乏连贯的堆栈跟踪也表明堆栈损坏。在 Fortran 中要查找的内容包括(像往常一样)数组边界违规或过程调用和定义之间的接口不匹配。 抱歉,我指的是-shared,而不是-dynamic 【参考方案1】:

这种错误是相当讨厌的。您可以尝试应用以下模式:

https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo015

在这种方法中,您可以在代码中“捕获”SIGSEGV。然后,您可以尝试使用 backtrace 函数获取回溯:

void *array[100];
size_t size;
size = backtrace (array, 100);
backtrace_symbols_fd (array, size, STDOUT_FILENO);

请注意,您不应在信号处理程序内部做太多事情。

然后,如果运气好,您将能够找出问题的原因。

另一种方法是使用 gdb 实际调试 JVM,看看那里会发生什么。

您可以在此处找到 JNI 调试示例:

http://www.owsiak.org/?p=2095

或这里:

https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNoD001

或这里:

https://youtu.be/8Cjeq4l5COU

如前所述,尝试在 Fortran 代码中启用边界检查。有时会有所帮助。

我希望它会有所帮助。

享受 JNI/JNA 的乐趣。

【讨论】:

您的第一个链接已失效。下次请考虑在答案中总结解决方案,而不是只提供外部链接。

以上是关于使用 JNA 使用本机 fortran 库时查找 SIGSEGV 原因的问题的主要内容,如果未能解决你的问题,请参考以下文章

在Linux环境下使用gfortran编译器生成fortran语言的.so共享对象文件 并使用JNA调用 带参方法

在Linux环境下使用gfortran编译器生成fortran语言的.so共享对象文件 并使用JNA调用 带参方法

使用Fortran共享库时名称不匹配

无法使用 JNA 找出本机类型的映射

使用 JNA 本机等待调用检测线程中断 (Windows)

JNA:本机库依赖项和JAR提取