使用 JNA 的应用程序中 JVM 崩溃可能有哪些原因?

问题描述 投票:0回答:1

我正在寻找 JNA 出现奇怪问题的可能原因。我有一个 Java 应用程序,它使用一堆共享库,这些库都是我和我的同事自制的、编程的。我们使用 JNA 5.x 将 SO 中的 C 函数公开给 java。 (Linux 上的 Java 11.20)。我们使用 Gradle 7.4 构建 Java 代码,使用 cmake 将 C 代码编译成 SO。

问题是,当我使用 Gradle 构建项目并按顺序执行所有测试时,JVM 崩溃了。在我添加了一个测试某个库中的函数的单元测试之后,这种情况就开始发生了。我收到以下错误:

# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fa08abac0ef, pid=129694, tid=129697
#
# JRE version: OpenJDK Runtime Environment (Red_Hat-11.0.20.0.8-1.fc38) (11.0.20+8) (build 11.0.20+8)
# Java VM: OpenJDK 64-Bit Server VM (Red_Hat-11.0.20.0.8-1.fc38) (11.0.20+8, mixed mode, sharing, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# C  [libc.so.6+0x990ef]

所以它一定是这个库中的东西,或者是我从中调用特定函数的方式。让这个问题对我来说很难的是,当我只执行一个单元测试时,它是绿色的。 JVM 没有问题,结果符合预期。

GDB 也没有给我任何真正的线索,或者至少我无法解释它们。当我调试gradle进程时,我可以看到函数调用是成功的,因为返回值中有正确的结果,但是执行函数返回后,我在libc中遇到了问题。

Thread 2 "Test worker" received signal SIGSEGV, Segmentation fault.
0x00007fe3948420ef in unlink_chunk (p=p@entry=0x7fe38caedbe0, av=0x7fe38c000030) at malloc.c:1604
1604      if (chunksize (p) != prev_size (next_chunk (p)))                                                                                                                                                                    
(gdb) c
Continuing.

Thread 2 "Test worker" received signal SIGILL, Illegal instruction.
futex_wait (private=0, expected=2, futex_word=0x7fe38c000030) at ../sysdeps/nptl/futex-internal.h:146
Downloading source file /usr/src/debug/glibc-2.37-10.fc38.x86_64/nptl/../sysdeps/nptl/futex-internal.h
146       int err = lll_futex_timed_wait (futex_word, expected, NULL, private);                                                                                                                                               
(gdb) n
0x00007fe394317d10 in crash_handler(int, siginfo_t*, void*) () from /usr/lib/jvm/java-11-openjdk-11.0.20.0.8-1.fc38.x86_64/lib/server/libjvm.so
(gdb) n
Single stepping until exit from function _ZL13crash_handleriP9siginfo_tPv,
which has no line number information.

Thread 20 "VM Periodic Tas" received signal SIGABRT, Aborted.
[Switching to Thread 0x7fe365fff6c0 (LWP 131363)]
__pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
44            return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;                                                                                                                                       
(gdb) n
Couldn't get registers: No such process.
(gdb) [Thread 0x7fe36476d6c0 (LWP 131400) exited]

非常感谢任何在哪里查找以及如何继续查找问题原因的想法。

java c jna
1个回答
0
投票

在没有看到 Java 实现的情况下,很难准确地确定原因,但是来自本机端的错误清楚地表明您正在处理不属于您的本机内存:

Thread 2 "Test worker" received signal SIGSEGV, Segmentation fault.
0x00007fe3948420ef in unlink_chunk (p=p@entry=0x7fe38caedbe0, av=0x7fe38c000030) at malloc.c:1604
1604      if (chunksize (p) != prev_size (next_chunk (p)))                                                                                                                                                                    

指向这段代码:

* Take a chunk off a bin list.  */
static void
unlink_chunk (mstate av, mchunkptr p)
{
  if (chunksize (p) != prev_size (next_chunk (p)))
    malloc_printerr ("corrupted size vs. prev_size");

这些宏最终会调用

(p)->mchunk_size
(p)->mchunk_prev_size
;但 Java 进程很可能不拥有与
p
相关的内存,因此崩溃。可能您已经释放了它,或者可能
p
来自一些不应该释放的字节组。

对此进行调试需要遵循与本机函数调用相关的 Java/JNA 端和本机端内存分配。如果在Java端分配,则必须在Java端释放;如果您在本机端分配,则可以使用适当的本机 API 来释放该分配。您可能两者都在做。

JNA 的一个常见问题是,包含内存分配的对象可能在某些时候无法访问,并且有资格进行垃圾回收;本机内存作为该过程的一部分被释放。确保保留对与该内存分配关联的任何 Java 对象的强引用(

Structure
Memory
等)。

另一个潜在的候选者是堆栈损坏,即您从一组无意的字节中发送了指针地址;当本机函数调用中的类型映射不正确时,可能会发生这种情况。这可能是这里的罪魁祸首,释放内存的调用自行工作,但使用它运行其他测试可能会损坏堆栈。

© www.soinside.com 2019 - 2024. All rights reserved.