繁体   English   中英

什么可能导致std :: difftime创建SIGBUS崩溃?

[英]What could cause std::difftime to create a SIGBUS crash?

今天,我不得不惊骇地意识到,我的C ++模拟程序在运行12天后崩溃了,仅在运行结束前几行就崩溃了,只剩下一个(截断的)核心转储。

使用gdb对核心转储进行分析后发现,

程序以信号SIGBUS,总线错误终止。

并且崩溃发生在我的代码的以下行:

seconds = std::difftime(stopTime, startTime); // seconds is of type double

变量stopTimestartTime的类型为std::time_t ,我能够在崩溃时从核心转储中提取它们的值:

startTime: 1426863332
stopTime:  1427977226

difftime调用上方的堆栈跟踪如下所示:

#0  0x.. in _dl_fixup () from /lib64/ld-linux-x86-64.so.2
#1  0x.. in _dl_runtime_resolve () from /lib64/ld-linux-x86-64.so.2

我编写了一个小程序来重现错误,但没有成功。 仅使用上述值调用std::difftime(stopTime, startTime)不会导致SIGBUS崩溃。 当然,我不希望这种情况再次发生。 我已经以相同的执行时间成功地执行了几次相同的程序(尽管使用了不同的参数)。 可能导致此问题的原因是什么?将来如何预防?

这是一些其他系统信息。

GCC: (SUSE Linux) 4.8.1 20130909 [gcc-4_8-branch revision 202388]  
Linux Kernel: 3.11.10-25-desktop, x86_64
C++ standard library: 6.0.18

编辑

这里还有一些背景。 首先,完整的堆栈跟踪(省略号[..]我的):

#0  0x00007f309a4a5bca in _dl_fixup () from /lib64/ld-linux-x86-64.so.2
#1  0x00007f309a4ac195 in _dl_runtime_resolve () from /lib64/ld-linux-x86-64.so.2
#2  0x0000000000465453 in CStopwatch::getTime (this=0x7fff0db48c60, delimiterHourMinuteSecondsBy="") at [..] CStopwatch.cpp:86
#3  0x00000000004652a9 in CStopwatch::stop (this=0x7fff0db48c60) at [..] CStopwatch.cpp:51
#4  0x0000000000479a0c in main (argc=33, argv=0x7fff0db499c8) at [..] coherent_ofdm_tsync_mse.cpp:998

问题发生在程序开头创建的CStopwatch类的对象中。 秒表从最顶部的main()开始。 模拟完成后,将调用函数CStopwatch::stop( )

秒表类的构造函数:

/*
 * Initialize start and stop time on construction
 */
CStopwatch::CStopwatch()
{
  this->startTime = std::time_t( 0 );
  this->stopTime = std::time_t( 0 );
  this->isRunning = false;
}

函数CStopwatch::stop( )

/*
 * Stop the timer and return the elapsed time as a string
 */
std::string CStopwatch::stop( )
{
  if ( this->isRunning ) {
    this->stopTime = std::time( 0 );
  }
  this->isRunning = false;

  return getTime( );
}

函数CStopwatch::getTime()

/*
 * Return the elapsed time as a string
 */
std::string CStopwatch::getTime( std::string delimiterHourMinuteSecondsBy )
{
  std::ostringstream timeString;

// ...some string init      

  // time in seconds
  double seconds;

  if ( this->isRunning ){
    // return instantaneous time
    seconds = std::difftime(time(0), startTime);
  } else {
    // return stopped time
    seconds = std::difftime(stopTime, startTime); // <-- line where the
                                                  // program crashed
  }

  // ..convert seconds into a string

  return timeString.str( );
}

在程序开始时,将CStopwatch::start( )

/*
 * Start the timer, if watch is already running, this is effectively a reset
 */
void CStopwatch::start( )
{
  this->startTime = std::time( 0 );
  this->isRunning = true;
}

看起来std::difftime在它的第一次访问中被延迟加载了; 如果某些运行时链接程序的内部状态在程序中的其他位置已损坏,则可能导致此情况。

请注意, _dl_runtime_resolve必须在std::difftime调用开始之前完成,因此错误不太可能与您的时间值有关。 您可以通过在gdb中打开核心文件轻松地进行验证:

(gdb) frame 2 # this is CStopwatch::getTime
(gdb) print this
(gdb) print *this

etc. etc.

如果gdb能够读取并解析该地址,并且这些值看起来很合理,那么这绝对不会在运行时引起SIGBUS。 或者,您的堆栈有可能被砸碎了。 如果_dl_fixup正在准备蹦床跳跃,而不仅仅是处理重定位等; 我们无法确定是否不看代码,但可以检查堆栈本身:

(gdb) print %rsp
(gdb) x/16xb $rsp-16 # print the top 16 bytes of the stack

尝试解决的简单方法是设置LD_BIND_NOW环境变量并在启动时强制使用符号解析。 但是,这只是隐藏了问题,因为某些 地方的内存仍在损坏,而我们只是隐藏了症状。

至于正确解决问题的方法-即使短期运行未显示错误,也可能会发生一些内存损坏,但没有症状。 尝试在valgrind下运行较短的模拟,并修复所有警告和错误,除非您确定它们是良性的。

程序在Linux上可能会收到SIGBUS原因仅有几个。 该问题的答案中列出了几个。

在崩溃时查看/var/log/messages ,很可能会发现磁盘故障或其他导致内核故障的原因。

另一个(不太可能)的可能性是有人程序运行更新了libstdc++.so.6 这样做不正确(通过覆盖现有文件,而不是删除它并在其位置创建新文件)。

无需进一步说明就无法说出,但是:

  • this可能为null或损坏
  • startTime可以为空引用
  • stopTime可以为空引用

我会建议你上线设置一个断点,并打印出stopTimestartTime ,但你已经几乎是通过查看核心文件来完成。

似乎在链接函数时出了点问题。可能是您针对链接到的标准库中的一组不同的头进行编译吗?

它可能与内存有关:

  • 如果这是深层嵌套,则可能只是堆栈溢出。
  • 如果这是第一次被调用,可能是它正在尝试为该库分配内存,将其加载并链接,但由于达到内存限制而失败

如果此代码路径被调用了很多次,并且从未在其他地方崩溃,那么也许该是通宵运行memtest86的时候了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM