【发布时间】:2014-06-09 09:12:12
【问题描述】:
我一直在编写一个生成子进程的程序,并调用waitpid 等待子进程终止。代码如下:
// fork & exec the child
pid_t pid = fork();
if (pid == -1)
// here is error handling code that is **not** triggered
if (!pid)
{
// binary_invocation is an array of the child process program and its arguments
execv(args.binary_invocation[0], (char * const*)args.binary_invocation);
// here is some error handling code that is **not** triggered
}
else
{
int status = 0;
pid_t res = waitpid(pid, &status, 0);
// here I see pid_t being a positive integer > 0
// and status being 11, which means WIFEXITED(status) is 0.
// this triggers a warning in my programs output.
}
waitpid 的联机帮助页指出WIFEXITED:
WIFEXITED(status)
returns true if the child terminated normally, that is, by calling exit(3) or
_exit(2), or by returning from main().
我的意思是它应该在成功时返回一个整数!= 0,这在我的程序执行中不会发生,因为我观察到 WIFEXITED(status) == 0
但是,从命令行执行相同的程序会产生$? == 0,而从 gdb 开始会产生:
[Inferior 1 (process 31934) exited normally]
程序运行正常,除了触发的警告,这让我觉得这里发生了其他事情,我错过了。
编辑:
正如下面在 cmets 中所建议的,我检查了孩子是否通过 segfault 终止,实际上,WIFSIGNALED(status) 返回 1,WTERMSIG(status) 返回 11,即 SIGSEGV。
但我不明白的是,为什么通过 execv 的调用会因段错误而失败,而通过 gdb 或 shell 的相同调用会成功?
EDIT2:
我的应用程序的行为很大程度上取决于子进程的行为,特别是子进程在声明为__attribute__ ((destructor)) 的函数中写入的文件。在waitpid 调用返回后,此文件存在并正确生成,这意味着段错误发生在另一个析构函数的某个地方,或者我无法控制的某个地方。
【问题讨论】:
-
状态 11 表示孩子收到信号 11,
SIGSEGV。非信号退出是传递给_exit或exit或由main返回的值的低8 位的256 倍。如果您在具有strace的平台(如Linux)上,请使用它(带有-f标志)来查看孩子是否由于对execv的错误调用或在成功执行之后获得了信号。 -
@robmayoff 你是对的!我不知道 status 变量的低字节保存生成进程的退出状态以及信号 id 的事实。感谢您指出这一点!
-
“但我不明白的是,为什么通过 execv 的调用会因段错误而失败” ...
args.binary_invocation看起来如何?它来自哪里,你创造它? -
@Dabo 是的,args.binary_invocation 是一个 NULL 终止的 char 指针数组,它是子应用程序的名称及其参数。我已经验证了数组是正确的。
-
@robmayoff 由于您的评论,我找到了段错误的原因 - 问题是我的应用程序改变了子进程的环境,我没有在我的独立测试中重现,这就是为什么segfault 隐藏在 exec 环境之外。我想为此感谢你,因为你把我送到了正确的方向。所以,如果你想让你的 cmets 成为一个答案,我很乐意接受它:)