分叉后libev中的分段错误

Posted

技术标签:

【中文标题】分叉后libev中的分段错误【英文标题】:Segmentation fault in libev after fork 【发布时间】:2013-04-19 09:44:04 【问题描述】:

我想用libev 制作一个示例应用程序。我想在键盘输入上有一个观察者,它将解析几个命令,如“开始”“停止”“退出”。在“开始”时,我想创建一个管道并派生应用程序以在子级中启动一些工作程序(例如 ffmpegexec() 或只是一些打印一些字符的循环),并在父级的该管道上设置一个观察者将输出打印到控制台。在“停止”命令中,我想杀死一个孩子并移除一个观察者。

我已经实现了这个程序,但是在 fork 之后,当孩子运行时,我总是在键盘输入上遇到段错误。

起初我以为是因为STDIN 可以在孩子和父母之间共享。我试图分离孩子,在孩子中关闭STDIN。然后我尝试了dupSTDIN,并在开头关闭了父级中的默认STDIN,并在重复的STDIN 上设置了一个观察者。我还尝试在分叉之前关闭 STDOUT/ERR 描述符,并在分叉之后将它们恢复到父级中。

我停止并在user_input 回调中启动user_input 观察者,以防万一这有帮助。

然后我尝试在一个子进程中执行ev_default_fork()ev_loop_fork()(这不是必需的,因为我想在fork 之后执行exec(),或者在任何情况下子循环都不会获得控制)但没有成功。

我还尝试使用不同的后端(select 而不是epoll)。

我还试图忽略一些信号,例如 SIGHUP SIGPIPE SIGCHILD

我还注意到我在fork() 之后的输入会导致段错误,并且 bash 将其作为命令获取,所以如果我执行类似这样的操作(使用“>”,我表示自己手写输入,使用“

> $ ./libev_example
> start
< Debug: fork data got: 
< [Data got from child through pipe] 
> asd
< Segmentation fault (core dumped)
< $ asd
< bash: asd: command not found...

然后我从源代码构建libev 并尝试调试。段错误发生在ev.c:1698

  if (expect_false (w_->pending))
      pendings [pri][w_->pending - 1].events |= revents;
  else

pri 的值为 4,据我所知,这是一个优先事项。 pendings[4]0x0 所以会发生段错误。当程序不崩溃时,代码进入else 分支。

epoll 返回的 fd 是 0,但无论如何我都没有使用 0 作为 fd。此外,对于 0,loop-&gt;anfds 中有一个观察者,它对我的​​ user_input 回调有一个回调。在之前的迭代中,当我输入任何字符串时,没有事件为 0。我检查了管道 fds,它们也有一个数字,然后是 0。

我不知道这里发生了什么以及我做错了什么。我可以在这里放一些代码,但那里没有什么特别的。这篇文章够大,如果有人要代码,我会在稍后发布。

谢谢。

【问题讨论】:

【参考方案1】:

好的。用gdb一段时间解决了这个问题。我在我的代码中发现了几个与 libev 或 fork 没有直接联系的错误。

导致这种奇怪行为的问题是我的错误输入,由于我的注意力不集中而没有注意到。我继承了标准 ev_io 结构,但出于某种原因我做了这个:

typedef struct lee_user_input_event_t
    struct ev_io *event;
    struct lee_process_data_t *child_process_data;
...
;

而不是这个:

typedef struct lee_user_input_event_t
    struct ev_io event;
    struct lee_process_data_t *child_process_data;
...

因此,将回调中的事件指针转换为我自己的结构是一场彻底而巨大的灾难。

【讨论】:

以上是关于分叉后libev中的分段错误的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中的向量中键入所有值后出现分段错误(核心转储)

C 中 Trie 实现中的分段错误

这段代码一次执行良好,另一次出现分段错误

分配时出现分段错误[重复]

链表中的分段错误

C++:当我添加看似无关的代码行时,分段错误消失了