【问题标题】:Threads looping system() and cout corrupt the stack线程循环 system() 和 cout 损坏堆栈
【发布时间】:2014-07-20 21:43:09
【问题描述】:

运行以下代码的进程因分段错误而崩溃:

#include <stdlib.h>
#include <iostream>
#include <pthread.h>

void* f( void* )
{
   while( true )
   {
      // It crashes inside this call (with cerr, too).
      std::cout << 0;
   }
   return NULL;
}

int main()
{
   pthread_t t;
   pthread_create( &t, NULL, &f, NULL );

   while( true )
   {
      // It crashes with any script/app; true is just simple.
      system( "true" );
   }
   return 0;
}

它在几秒钟内每隔一次执行就会崩溃(输出有数千到数百万个“0”)。它使用上面的代码使cout &lt;&lt; 0 调用中的一些函数崩溃。根据在f() 中调用的额外函数或放入堆栈的数据,它会在不同的地方崩溃。在 gdb 中,有时堆栈对于函数调用的顺序没有意义。由此我推断堆栈已损坏。

我发现有一些problems with multi-threaded applications calling fork()(另见两个提到堆栈损坏的 cmets)。如果未将文件描述符设置为FD_CLOEXEC,则分叉/克隆进程会复制文件描述符。但是,没有明确创建的文件描述符。 (我尝试在fileno( stdout ) 和fileno( stderr ) 上设置FD_CLOEXEC,但没有积极变化。)

即使没有明确的文件描述符,我也不能混合线程和fork() 吗?我是否只需将system() 调用替换为等效功能?或者内核中是否存在导致此崩溃的错误并已在 2.6.30 之后修复?

其他详情

我在 ARM AT91 处理器 (armv5tejl) 上运行它,并使用 GCC 4.3.2 编译的 Linux 2.6.30(为我的特定外围设备集提供了一些覆盖和补丁)。

Linux 2.6.30 #1 Thu May 29 15:43:04 CDT 2014 armv5tejl GNU/Linux

我一直在 [cross] 使用 -g 和 -O0 编译它,但没有它们它仍然会崩溃:

arm-atmel-linux-gnueabi-g++ -o system_thread system_thread.cpp -lpthread

我也尝试过-fstack-protector-all 标志:有时它会在__stack_chk_fail() 中崩溃,但有时其他函数指针或数据会损坏并且它会更早崩溃。

它加载的库(来自 strace):

libpthread.so.0
libstdc++.so.6
libm.so.6
libgcc_s.so.1
libc.so.6

注意:由于它有时不会崩溃,也不会真正响应^C,因此我通常在后台运行它:

$ killall -9 system_thread; rm -f log; system_thread >log &

我已经为几个不同的架构和 Linux 内核版本编译了这个程序,但我没有看到它在其他任何地方崩溃:

Linux 3.10.29 #1 Wed Feb 12 17:12:39 CST 2014 armv5tejl GNU/Linux
Linux 3.6.0-dirty #3 Wed May 28 13:53:56 CDT 2014 microblaze GNU/Linux
Linux 3.13.0-27-generic #50-Ubuntu SMP Thu May 15 18:06:16 UTC 2014 x86_64 x86_64 GNU/Linux
Linux 3.8.0-35-generic #50~precise1-Ubuntu SMP Wed Dec 4 17:25:51 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

编辑:请注意,在同一架构 (armv5tejl) 上,它不会在 Linux 3.10.29 中崩溃。此外,在具有相同版本的 Linux - 2.6.30 的我的“设备”(旧的服务器和客户端应用程序)的早期版本上运行时,它不会崩溃。所以操作系统的环境有一定的影响。

BusyBox v1.20.1 提供了sh,system() 调用。

【问题讨论】:

  • The system function is not thread-safe,但我不确定这是你的问题。
  • 我认为由于您使用的是无限循环,这就是为什么它可能会执行到堆栈已满然后它会损坏,所以尽量不要使用无限循环。
  • 顺便说一句,我无法重现崩溃。
  • 无限循环通常会导致整个系统无响应。对于现在流行的抢占式多任务模型,无限循环通常会导致程序消耗所有可用的处理器时间,但通常可以由用户终止
  • @ali786 - 这些无限循环已从我的常规程序中简化,这是一个不断处理来自客户端的消息的服务器。通常循环正在等待套接字接收或信号量。这是仍然崩溃的最简单的代码。

标签: c++ linux multithreading segmentation-fault


【解决方案1】:

这可以在使用您提到的 2.6.30 内核的 ARM 处理器上重现,但不能在 master 中重现。我们可以使用git bisect 来查找此错误的修复位置(大约需要 16 次迭代)。请注意,由于git bisect 是用来查找回归的,但在这种情况下,master 是“好”但过去的版本是“坏”,我们需要reverse the meanings of "good" and "bad"。

二分法发现的罪魁祸首是this commit,用于修复涉及 fork() 的“用户空间数据损坏实例”。此症状与您描述的症状非常相似,并且还可能损坏堆栈外的内存。将此提交和 the required parent 反向移植到 2.6.30 内核后,您发布的代码不再崩溃。

【讨论】:

  • 应用这些提交后,程序不再崩溃!谢谢!
猜你喜欢
  • 2012-08-02
  • 1970-01-01
  • 2016-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-10
相关资源
最近更新 更多