【发布时间】:2020-03-31 00:34:55
【问题描述】:
伙计们!我正在编写必须在尽可能多的 Linux 版本上安装和运行的软件,但我必须能够在单个 Jenkins slave 上编译它。
现在这主要是可行的。但是我遇到了一种情况,即特殊组合会在 Debian 10 上产生段错误,但不会在我众多其他受支持的 Linux 版本中产生段错误。我已经能够在 3 个不同的应用程序(其中一些已经工作多年)中重现这一点,包括我在下面列出的简化原型。
// g++ -g -o ttt -static tt.cpp
// The above compile of this code on Centos 6 will produce a segfault
// when run on Debian 10, but not on any other tested flavor of Linux.
// Dozens of them. The version of g++ is 4.7.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int _argc, char* _argv[])
{
srand(time(0));
printf("success\n");
return 0;
}
通过在 Debian 10 上使用 gdb 运行我的 3 个应用程序,我发现它在这些条件下会出现段错误。
- 必须使用 -static 标志编译它们。如果我不使用 -static,它可以正常工作,无论编译哪种风格。
- 他们必须调用 time() 函数。我如何称呼它并不重要,但它必须被调用。我尝试了通常的疑点,例如传递 NULL 指针和传递真实指针。静态编译应用程序时总是会出现段错误。
- 它们必须在 Centos 6 上编译并在 Debian 10 上运行。如果我在 Debian 10 上静态编译,原型可以正常工作。
所以这是我工作的限制条件。
- 我必须在一个 Linux 从站上编译,因为我只分发一个二进制文件。跟踪多个二进制文件以及哪个二进制文件适用于哪种 Linux 风格并不是真正的选择。
- 我必须静态编译,否则会在其他受支持的 Linux 版本上造成不兼容。
- 为了兼容性,我必须使用较旧的 Linux 版本。它不一定是 Centos,但它必须生成可在 Centos 以及许多其他版本上运行的二进制文件。
- 为了代码兼容性,我还必须使用 g++ 4.7。
在您的回答中,我希望有某种代码技巧。也许是 time() 函数的良好、可靠的替代品。或者对与 Debian 10 兼容的另一种 Linux 风格的建议。
谁能解释为什么像 time() 这样的基本的、无处不在的函数在 Debian 9 上完全兼容,但只有在 Centos 6 上静态编译时才会在 Debian 10 上出现段错误。 ..
编辑:
Centos 6 服务器上的 strace:
execve("./ttt", ["./ttt"], [/* 37 vars */]) = 0
uname({sys="Linux", node="testcent6", ...}) = 0
brk(0) = 0x238c000
brk(0x238d180) = 0x238d180
arch_prctl(ARCH_SET_FS, 0x238c860) = 0
brk(0x23ae180) = 0x23ae180
brk(0x23af000) = 0x23af000
gettimeofday({1585687633, 358976}, NULL) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f682c82f000
write(1, "success\n", 8success
) = 8
exit_group(0) = ?
+++ exited with 0 +++
Debian 10 服务器上的 strace:
execve("./ttt", ["./ttt"], 0x7fff0430dfd0 /* 18 vars */) = 0
uname({sysname="Linux", nodename="deletemedebian10", ...}) = 0
brk(NULL) = 0x1f6f000
brk(0x1f70180) = 0x1f70180
arch_prctl(ARCH_SET_FS, 0x1f6f860) = 0
brk(0x1f91180) = 0x1f91180
brk(0x1f92000) = 0x1f92000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xffffffffff600400} ---
+++ killed by SIGSEGV +++
Segmentation fault
【问题讨论】: