作者 | 描述 | 时间 |
---|---|---|
雨中星辰 | 2024-01-23 |
问题描述
在c代码中使用调用了jni的方法,不使用gdb时,正常运行,但只要通过gdb启动执行,程序就会core down崩溃
代码
[dcloud@40-152 /tmp/test2]$cat main.cpp
#include <jni.h>
#include <stdio.h>
int main() {
JavaVM *jvm;
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options[1];
// 设置JVM选项
options[0].optionString = "-Djava.class.path=/opt/zeus/javaLib/zeus-core-4.0.3.jar";
// 设置JavaVMInitArgs结构体
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_FALSE;
// 创建JVM虚拟机
jint res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
if (res < 0) {
printf("Error creating JVM\n");
return 1;
}
printf("create JVM success\n");
return 0;
}
编译
g++ -g -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -L${JAVA_HOME}/jre/lib/amd64/server -ljvm main.cpp -o main
直接执行
[dcloud@40-152 /tmp/test2]$./main
create JVM success
打印:create JVM success符合预期
使用gdb执行
[dcloud@40-152 /tmp/test2]$gdb ./main
GNU gdb (Debian 7.11.1-2~bpo8+1) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...done.
(gdb) r
Starting program: /tmp/test2/main
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x00007fffe5d712b4 in ?? ()
可以看到程序直接就崩溃了。
问题原因分析
Java 使用推测负载。如果指针指向可寻址内存,则加载成功。很少情况下,指针不指向可寻址内存,并且尝试加载会生成SIGSEGV,java运行时会拦截该内存,使内存再次可寻址,并重新启动加载指令。
不幸的是,如果涉及一些 JNI 代码,并且该代码SIGSEGV,GDB 也会很乐意忽略该信号,从而导致劣质(正在调试)进程的死亡。
调试java程序时,一般要这样做:
(gdb) handle SIGSEGV nostop noprint pass
命令说明:
(gdb) handle SIGSEGV nostop noprint pass
是 GDB(GNU 调试器)的命令,用于设置对 SIGSEGV 信号的处理方式。
SIGSEGV 是指当程序访问无效的内存地址或进行非法的内存操作时,操作系统会向程序发送的一个信号。这通常发生在出现段错误(Segmentation Fault)时。
该命令中的选项含义如下:
nostop
:表示当收到 SIGSEGV 信号时,GDB 不会停止程序的执行。即,不会在出现 SIGSEGV 时中断程序的执行,而是继续运行下去。
noprint
:表示当收到 SIGSEGV 信号时,GDB 不会打印相关信息。即,在出现 SIGSEGV 时,GDB 不会输出任何与该信号相关的消息。
pass
:表示当收到 SIGSEGV 信号时,GDB 将完全忽略该信号。即,不会对 SIGSEGV 信号进行任何处理。
通过使用这些选项,可以改变 GDB 对 SIGSEGV 信号的默认行为,使其不中断程序的执行,并且不打印或处理该信号。这在某些情况下可能有助于排查程序中的问题,但同时也需要注意,忽略 SIGSEGV 信号可能会隐藏潜在的错误或导致程序进一步崩溃。因此,在实际调试过程中,需要根据具体情况谨慎使用该命令。
测试
[dcloud@40-152 /tmp/test2]$gdb ./main
GNU gdb (Debian 7.11.1-2~bpo8+1) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...done.
(gdb) handle SIGSEGV nostop noprint pass
Signal Stop Print Pass to program Description
SIGSEGV No No Yes Segmentation fault
(gdb) r
Starting program: /tmp/test2/main
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7fc8700 (LWP 15458)]
[New Thread 0x7fffe3f7e700 (LWP 15459)]
[New Thread 0x7fffe3e7d700 (LWP 15460)]
[New Thread 0x7fffe3d7c700 (LWP 15461)]
[New Thread 0x7fffe3c7b700 (LWP 15462)]
[New Thread 0x7fffe3b7a700 (LWP 15463)]
[New Thread 0x7fffe3a79700 (LWP 15464)]
[New Thread 0x7fffe3978700 (LWP 15465)]
[New Thread 0x7fffe3877700 (LWP 15466)]
[New Thread 0x7fffe3776700 (LWP 15467)]
[New Thread 0x7fffe3675700 (LWP 15468)]
[New Thread 0x7fffe3574700 (LWP 15469)]
[New Thread 0x7fffe3473700 (LWP 15470)]
[New Thread 0x7fff9f0f0700 (LWP 15471)]
[New Thread 0x7fff9efef700 (LWP 15472)]
[New Thread 0x7fff9eeee700 (LWP 15473)]
[New Thread 0x7fff9ea89700 (LWP 15474)]
[New Thread 0x7fff9e988700 (LWP 15475)]
[New Thread 0x7fff9e887700 (LWP 15476)]
[New Thread 0x7fff9e786700 (LWP 15477)]
[New Thread 0x7fff9e685700 (LWP 15478)]
[New Thread 0x7fff9e584700 (LWP 15479)]
[New Thread 0x7fff9e483700 (LWP 15480)]
[New Thread 0x7fff9e382700 (LWP 15481)]
[New Thread 0x7fff9e281700 (LWP 15482)]
[New Thread 0x7fff9e180700 (LWP 15483)]
[New Thread 0x7fff9e07f700 (LWP 15484)]
[New Thread 0x7fff9df7e700 (LWP 15485)]
[New Thread 0x7fff9de7d700 (LWP 15486)]
[New Thread 0x7fff9dd7c700 (LWP 15487)]
[New Thread 0x7fff9dc7b700 (LWP 15488)]
create JVM success
[Thread 0x7fff9dc7b700 (LWP 15488) exited]
[Thread 0x7fff9dd7c700 (LWP 15487) exited]
[Thread 0x7fff9de7d700 (LWP 15486) exited]
[Thread 0x7fff9df7e700 (LWP 15485) exited]
[Thread 0x7fff9e07f700 (LWP 15484) exited]
[Thread 0x7fff9e180700 (LWP 15483) exited]
[Thread 0x7fff9e281700 (LWP 15482) exited]
[Thread 0x7fff9e382700 (LWP 15481) exited]
[Thread 0x7fff9e483700 (LWP 15480) exited]
[Thread 0x7fff9e584700 (LWP 15479) exited]
[Thread 0x7fff9e685700 (LWP 15478) exited]
[Thread 0x7fff9e786700 (LWP 15477) exited]
[Thread 0x7fff9e887700 (LWP 15476) exited]
[Thread 0x7fff9e988700 (LWP 15475) exited]
[Thread 0x7fff9ea89700 (LWP 15474) exited]
[Thread 0x7fff9eeee700 (LWP 15473) exited]
[Thread 0x7fff9efef700 (LWP 15472) exited]
[Thread 0x7fff9f0f0700 (LWP 15471) exited]
[Thread 0x7fffe3574700 (LWP 15469) exited]
[Thread 0x7fffe3675700 (LWP 15468) exited]
[Thread 0x7fffe3776700 (LWP 15467) exited]
[Thread 0x7fffe3877700 (LWP 15466) exited]
[Thread 0x7fffe3978700 (LWP 15465) exited]
[Thread 0x7fffe3a79700 (LWP 15464) exited]
[Thread 0x7fffe3b7a700 (LWP 15463) exited]
[Thread 0x7fffe3c7b700 (LWP 15462) exited]
[Thread 0x7fffe3d7c700 (LWP 15461) exited]
[Thread 0x7fffe3e7d700 (LWP 15460) exited]
[Thread 0x7fffe3f7e700 (LWP 15459) exited]
[Thread 0x7ffff7fc8700 (LWP 15458) exited]
[Thread 0x7ffff7fca740 (LWP 15454) exited]
[Inferior 1 (process 15454) exited normally]
(gdb)
可以看到,在进入gdb后,执行handle SIGSEGV nostop noprint pass
命令后,再执行程序,确实就正常了。
参数文献:
https://stackoverflow.com/questions/54365079/printing-backtraces-when-debugging-java
https://stackoverflow.com/questions/27241575/why-does-java-app-crash-in-gdb-but-runs-normally-in-real-life
https://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/signals.html