waitpid - WIFEXITED返回0虽然孩子正常退出

时间:2014-04-24 07:47:00

标签: c fork waitpid execv

我一直在编写一个生成子进程的程序,并调用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的{​​{1}}州的联合页面:

WIFEXITED

我的意思是它应该返回一个整数!= 0成功,这在我的程序执行中没有发生,因为我观察WIFEXITED(status) returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().

但是,从命令行执行相同的程序会导致WIFEXITED(status) == 0,并从gdb开始导致:

$? == 0

程序运行正常,除了触发警告,这让我觉得其他事情正在发生,我不知道。

修改
 如下面评论中所述,我检查了孩子是否通过段错误终止,确实[Inferior 1 (process 31934) exited normally] 返回1,而WIFSIGNALED(status)返回11,即WTERMSIG(status)

我不明白的是,为什么通过execv进行的调用会因为段错误而失败,而通过gdb或shell进行同一调用会成功?

EDIT2:
我的应用程序的行为在很大程度上取决于子进程的行为,尤其是子进程在声明为SIGSEGV的函数中写入的文件。在__attribute__ ((destructor))调用返回后,此文件存在且生成正确,这意味着段错误发生在另一个析构函数中的某个位置,或者在我无法控制的位置。

1 个答案:

答案 0 :(得分:7)

在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是否正在发出信号。