【问题标题】:Strange situation while redirecting debug statements to stderr将调试语句重定向到标准错误时的奇怪情况
【发布时间】:2012-01-02 19:11:39
【问题描述】:

我陷入了困境。我正在开发嵌入式设备(基于 linux OS 和 ARM 处理器,32 位)。它是一种触摸屏设备,具有许多外围设备,如智能卡读卡器、GPS、GPRS。我正在用 C 编码,当我重定向调试语句时,我的应用程序在一段时间后崩溃,如下所示。我有大约 300 个调试打印语句,我正在使用这个函数(如宏)打印。该设备也可以通过 USB 电缆连接到系统终端。当我在我的系统终端中打印这些调试语句时,应用程序不会在任何地方崩溃,但是当我不使用我的计算机终端并在设备中运行应用程序时,它会在一段时间后崩溃:

#ifdef DEBUG_TEST
  #define DEBUG_TEST 1
  #else
  #define DEBUG_TEST 0
  #endif

  #define DEBUG_PRINT(fmt, ...) \
             do { if (DEBUG_TEST) fprintf(stderr, fmt, ##__VA_ARGS__); } while (0)

但是当我关闭这些调试语句时,应用程序不会在任何地方崩溃。我不明白为什么会这样。
根据我的猜测,由于设备没有自己的标准终端,因此打印这些调试消息会创建一个缓冲区,因此一段时间后它会崩溃,而另一方面,当我关闭调试语句时,它工作正常.请提出为什么会发生这种情况?

【问题讨论】:

  • 它究竟是如何崩溃的?段错误?被内核杀死?其他?
  • 您可以选择在 GDB 下运行它,还是收集核心转储?
  • 如果我不得不猜测,我会说调试语句不是问题,它们只是在引发heisenbug
  • 只有当我打开调试语句并仅在设备上运行它而不使用我的系统终端时才会崩溃(意味着没有将设备连接到我的系统)..因此我无法追踪在哪里以及为什么它崩溃了......
  • 我个人的猜测是 stderr 实现内部的一些缓冲区溢出。至少,当它没有连接到某个设备时,我会使用 freopen() stderr 来写入文件。这应该可以避免问题或更好地指示发生崩溃的地方。

标签: c++ c linux embedded


【解决方案1】:

也许您的 DEBUG_PRINT 调用之一的参数之一导致 fprintf 的字符串插值器例程引用无效内存?例如,您的代码中的类似内容会使您的应用在 fprintf() 中崩溃:

const char * badPointer = (const char *) 0xDEADBEEF;  // deliberately pointing to invalid memory
DEBUG_PRINT("Crashing now!  %s\n", badPointer);

...要么,要么系统的 stdio 或 USB 实现中存在导致崩溃的错误。

为了缩小范围,您可以尝试注释掉各种 DEBUG_PRINT 语句,直到崩溃消失(此时您可以合理地怀疑它是导致崩溃的现已注释掉的 DEBUG_PRINT 语句之一,并且在你找出罪魁祸首之前评论一些东西)......或者如果你怀疑 fprintf() 中存在错误,你可以像这样进行折磨测试:

while(1) DEBUG_PRINT("I think I %s!\n", "can");

... 并查看运行是否会为您提供预期的输出(字符串的无限输出)或崩溃。如果它崩溃了,那么这表明你的程序之外存在错误。

【讨论】:

    【解决方案2】:

    您只是要更改这些语句,还是要从调试版本转到发布版本?从调试版本切换到发布版本会改变优化和内存填充等内容,因此您的崩溃可能是由于这些原因而在非调试中发生的。

    如果您更改的只是调试跟踪的开启和关闭,我建议您非常仔细地检查所有格式参数(%s、%d 等)并确保您没有将变量作为错误类型传递.

    【讨论】:

    • 最近的 GCC 应该单独使用 -Wall-Wformat 发现格式参数不匹配。
    【解决方案3】:

    如何在没有控制终端的情况下运行应用程序? 您可以尝试以下方法:

    在连接终端的情况下运行您的应用程序,但 stderr 已重定向

    ./yourapp 2>/dev/null
    

    ./yourapp 2>somefile.log
    

    看看它是否仍然崩溃。如果要转储核心文件,请不要忘记执行 ulimit -c unlimited。

    如果你有一个基于 busybox 的用户空间,你可以尝试 在循环缓冲区模式下使用 syslogd,并通过调用 syslog 替换您的 fprintf(stderr, ...),看看它是否仍然崩溃。

    【讨论】:

      猜你喜欢
      • 2014-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-14
      • 1970-01-01
      • 2012-05-26
      相关资源
      最近更新 更多