我试图理解为什么segfault消息的行为会因执行环境而异。
我有以下C代码,我正在使用它来故意触发segfault:
#include <stdio.h>
int main() {
int* p = NULL;
printf("%dn", *p);
}
在本地Linux上,当我编译此代码并执行生成的二进制文件时,即使我将stdout和stderr重定向到/dev/null
:,我也会看到segfault消息
$ ./segfault > /dev/null 2>&1
Segmentation fault (core dumped)
$
在Jenkins的Docker容器上,我编译并运行完全相同的C代码。我使用sh
步骤运行二进制文件,如下所示:
sh './segfault > /dev/null || true'
sh './segfault > /dev/null 2>&1 || true'
以下是Jenkins的输出:
+ ./segfault
Segmentation fault (core dumped)
+ true
+ ./segfault
+ true
正如您所看到的,segfault消息正在Jenkins中写入stderr(您可以从以下内容中看到这一点:当我不重定向到stderr时,消息会出现,但如果我重定向到stderr,消息不会出现(。但是在我的本地Linux上,segfault消息并没有写入stderr。
我验证了在本地Linux系统中交互式运行Docker容器时,将stdout和stderr重定向到/dev/null
也会导致容器的交互式shell输出中出现segfault消息:
$ gcc segfault.c
$ ./a.out >/dev/null 2>&1
Segmentation fault (core dumped)
我查看了sh
步骤的Java源代码,但对我来说,没有什么能成为Jenkins中这种不同行为的原因(但很可能我错过了什么(。
我的本地Linux是Ubuntu 20.04。我在Jenkins上使用的Docker镜像是gcc镜像。两者都使用x86_64体系结构。
在我的本地Linux上,以下是我的内核版本和内核版本:
$ uname -rv
5.13.0-30-generic #33~20.04.1-Ubuntu SMP Mon Feb 7 14:25:10 UTC 2022
这与gcc映像的内核版本和内核版本(在撰写本文时(完全匹配。
我的本地Linux有gcc 9.4.0,(在撰写本文时(gcc映像有gcc 12.2.0。
为什么詹金斯的行为与当地不同?
原因是以下原因之一吗?还是别的什么?
- Docker容器和非Docker Linux之间的区别
- 我编译的gcc版本的差异
- 一些神奇的詹金斯的东西
它是调用./segfault
的shell。如果您在计算机上切换到dash
并运行相同的命令,您也不会在那里看到Segmentation fault消息。
- 定义任何变量/对象时,始终初始化它
- 使用任何指针时,只有在不为NULL时才使用它们
- 下面是调用用户定义函数"的示例程序;mysig";当接收到SIGSEGV信号时。当我们使用NULL指针时,程序接收信号SIGSEGV(分段错误(。我已经更新了代码;mysig";当分段故障发生时。一旦发生这种情况,它就将创建核心转储文件作为默认功能。一旦接收到该信号
- 在执行程序之前:
$ ulimit -c unlimited
$ ./a.out
以上程序将创建一个核心文件。使用核心文件,我们可以根据您的操作系统使用gdb.exe/gdb/dbx分析程序崩溃的位置。gdb在线教程:
https://www.tutorialspoint.com/gnu_debugger/index.htm
示例程序:
#include <sys/signal.h>
#include <stdio.h>
void mysig( int sig)
{
switch( sig )
{
case SIGSEGV:
printf("Never use NULL pointern");
signal( SIGSEGV, SIG_DFL);
break;
default:
printf( "Other signal: %dn", sig);
}
}
int main()
{
int* p = NULL;
signal( SIGSEGV, mysig);
if ( NULL == p )
{
printf("Never use NULL pointern");
}
else
{
printf("%dn", *p);
}
printf( "Make call to mysig by using NULL pointern");
printf("%dn", *p);
return 0;
}
样本输出:
$ gcc -g -Wall 73596388.cpp -o ./a.out
$ ./a.out
Never use NULL pointer
Make call to mysig by using NULL pointer
Never use NULL pointer
Segmentation fault (core dumped)
$ # I compiled using bash.exe/gcc.exe at windows:
$ gdb a.out
Reading symbols from a.out...
(gdb) break main
Breakpoint 1 at 0x1004010d8: file 73596388.cpp, line 17.
(gdb) run
Starting program: ./a.out
[New Thread 10964.0x219c]
[New Thread 10964.0x2090]
[New Thread 10964.0x1dd4]
Thread 1 "a.out" hit Breakpoint 1, main () at 73596388.cpp:17
17 int* p = NULL;
(gdb) next
18 signal( SIGSEGV, mysig);
(gdb) next
19 if ( NULL == p )
(gdb) next
21 printf("Never use NULL pointern");
(gdb) next
Never use NULL pointer
27 printf( "Make call to mysig by using NULL pointern");
(gdb) next
Make call to mysig by using NULL pointer
28 printf("%dn", *p);
(gdb) step
Thread 1 "a.out" received signal SIGSEGV, Segmentation fault.
0x0000000100401136 in main () at 73596388.cpp:28
28 printf("%dn", *p);
(gdb) step
Never use NULL pointer
Thread 1 "a.out" received signal SIGSEGV, Segmentation fault.
0x0000000100401136 in main () at 73596388.cpp:28
28 printf("%dn", *p);
(gdb) step
0 [main] a.out 33539 cygwin_exception::open_stackdumpfile: Dumping stack trace to a.out.stackdump
[Thread 10964.0x2adc exited with code 35584]
[Thread 10964.0x2090 exited with code 35584]
[Thread 10964.0x219c exited with code 35584]
[Inferior 1 (process 10964) exited with code 0105400]
(gdb)