【问题标题】:waitpid - WIFEXITED returning 0 although child exited normallywaitpid - 尽管子进程正常退出,WIFEXITED 返回 0
【发布时间】: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。非信号退出是传递给_exitexit 或由main 返回的值的低8 位的256 倍。如果您在具有strace 的平台(如Linux)上,请使用它(带有-f 标志)来查看孩子是否由于对execv 的错误调用或在成功执行之后获得了信号。
  • @robmayoff 你是对的!我不知道 status 变量的低字节保存生成进程的退出状态以及信号 id 的事实。感谢您指出这一点!
  • “但我不明白的是,为什么通过 execv 的调用会因段错误而失败” ...args.binary_invocation 看起来如何?它来自哪里,你创造它?
  • @Dabo 是的,args.binary_invocation 是一个 NULL 终止的 char 指针数组,它是子应用程序的名称及其参数。我已经验证了数组是正确的。
  • @robmayoff 由于您的评论,我找到了段错误的原因 - 问题是我的应用程序改变了子进程的环境,我没有在我的独立测试中重现,这就是为什么segfault 隐藏在 exec 环境之外。我想为此感谢你,因为你把我送到了正确的方向。所以,如果你想让你的 cmets 成为一个答案,我很乐意接受它:)

标签: c fork waitpid execv


【解决方案1】:

在 Unix 和 Linux 系统上,从 waitwaitpid(或任何其他 wait 变体)返回的状态具有以下结构:

bits   meaning

0-6    signal number that caused child to exit,
       or 0177 if child stopped / continued
       or zero if child exited without a signal

 7     1 if core dumped, else 0

8-15   low 8 bits of value passed to _exit/exit or returned by main,
       or signal that caused child to stop/continue

(请注意,Posix 没有定义位,只是宏,但这些是至少 Linux、Mac OS X/iOS 和 Solaris 使用的位定义。另请注意,waitpid 仅在以下情况下返回停止事件您将WUNTRACED 标志传递给它,如果您将WCONTINUED 标志传递给它,则继续事件。)

因此,状态 11 表示孩子因信号 11 而退出,即SIGSEGV(同样,不是 Posix,而是传统上)。

要么您的程序将无效参数传递给execv(这是一个围绕execve 或其他内核特定调用的C 库包装器),要么当您execv 它和您运行它时子运行方式不同来自 shell 或 gdb。

如果您在支持strace 的系统上,请在strace -f 下运行您的(父)程序以查看execv 是否导致信号。

【讨论】:

    猜你喜欢
    • 2014-02-24
    • 2011-06-08
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 2014-05-16
    • 1970-01-01
    • 2013-04-03
    相关资源
    最近更新 更多