【问题标题】:Weird condition with static var that only appears on debug builds of gcc仅出现在 gcc 的调试版本中的静态 var 的奇怪情况
【发布时间】:2025-12-22 04:35:11
【问题描述】:

我有一个奇怪的情况,它只出现在 gcc -O0 -g 输出上,不在 gcc -O3 上,不在 MSVC 上,不在 MSVC 调试输出上。

void func(void) {
  static int enabled;

  if (!enabled) {
    // do stuff
    enabled = 1;
   }

}

仅在 gcc -O0 -g 上出现的问题是,有时 enabled 会返回 0。但并非总是如此,仅在程序执行中的一些罕见点。该函数通常循环通过它。什么会让它对此感到困惑?可以从外部更改“启用”吗?但它是在里面声明的。

编辑:有一种方法可以在函数内部将其设置为 0,但前面有一个根本不打印的大胖 printf [并且在测试中根本没有逻辑方式让它发生条件]。它似乎根本不涉及任何明确启用 = 0 的内容。

EDIT2:它只被主线程调用。

EDIT3:它变得更加奇怪。它不会出现在 linux gcc -O0 -g 上,而只会出现在 mingw-w64 [gcc -O0 -g] 上。

EDIT4:一个 rwatch 和 watch on enabled 似乎表明它在 if (!enabled) 的某些情况下被改变(这应该是只读的)。

EDIT5:在 oftc 的#mingw-w64 的帮助下,如果“布尔序列”被反转,它会出现“修复”,例如enabled 初始化为 1,然后设置为 0。“通过用非零值初始化静态变量,将其放入 .data 部分”“所以关于 lcomm 存在问题”“我假设您在代码中的其他地方”

【问题讨论】:

  • 记录这个函数是否可以被多个线程调用。
  • 不,只有主线程调用。
  • 该变量的初始化程序在哪里?因为现在它没有被初始化为任何东西——我假设你希望它最初是 0?另外你是如何确定它回到 0 的?
  • 它是静态的。它被初始化为 0。它回到 0,因为在“做事”中 printf 报告了它,并且我明确地 printf'ed 它的值。
  • 您是否尝试过使用 gdb 并在该变量上设置写入观察点?

标签: c debugging gcc gdb mingw


【解决方案1】:

我的猜测:你在某处有缓冲区溢出。 enabled 之前位于主内存中的变量被错误的大小覆盖,之后的所有内容也被覆盖。或者,您有一个覆盖它的杂散指针。

按照 thkala 的建议,进一步调试此问题的唯一有用方法是在 gdb 中添加一个观察点。

【讨论】:

  • 我找到了。这是在它之前执行的函数中的一个变量的明显溢出(一个短的 int,如果它进入 int,它会修复行为)。现在我只需要找出它的尺寸到底应该是多少才能使其防弹(不是绝对必要,但为什么不呢,呵呵)。
  • 哈,愚弄我(当我将它设置为 short int 时)的是那个特定的变量最终非常小。但是,在此过程中,它是更复杂的浮动计算的一部分。
  • 啊,更正,当短整数是写入它们的函数中的参数时会发生这种情况。这应该更容易,因为错误可能不符合他们所需的输入大小。
  • 是的,它是一个需要 UINT 的 Microsoft 函数。