0

我有一个指向**A另一个指针 ( ) 的指针 ( *B)。程序中的某个地方B正在损坏。但是,在存储之前B已损坏。并不总是位于相同的地址(并不总是相同)。但是 B 总是被相同的值破坏(总是相同的)。我知道这一点是因为我有一个损坏检测例程,它查看要存储的下一个值,所以我只知道它已经损坏的点。*AB&BB*A

我想要的(当然)是找出B损坏的地方。

我已经尝试过一个 gdb 观察点,它会自动在指向 ( )A的任何点上生成一个观察点,希望能够捕捉到它第一次存储在什么时候,在它不再存储之前,变得损坏,然后重新存储.A*AB*A*A*A

watch A
commands
  silent
  watch *A
  commands
    silent
    if *A == magicalcorruptedvalue
      where
    end
  end
end

但问题是,对于硬件观察点,太多的中间内容被存储在 上*A,所以我很快就用完了观察点。我没有尝试过软件观察点,因为它们不适用于线程。

在这一点上,我认为唯一的解决方案是返回并更仔细地阅读代码(总是一个不错的选择),构建更多的单元测试,或者创建一个专门的线程来不断扫描所有分配的内存以寻找这个值.

但是,我怀疑我不是第一个遇到这个问题的人。表达这个问题的更一般的方式可能是:当所有简单的技术都失败时,调试缓冲区溢出的技术是什么?

元参数:

  • 在 Linux 上

  • 这是在多线程回调样式的应用程序中。

4

1 回答 1

0

我想出了两个答案,其中一个实际上对我有用。

  1. 为工作使用正确的工具。gdb 用于调试程序流程。valgrind似乎更适合调试内存/缓冲区错误。使用 valgrind 运行程序,我很快就发现了错误。

  2. 理论上在gdb中实际上有一种方法可以做到这一点。*A在实践中,只有相对很少更改才会足够快。不是它在这个特定程序中改变的 10k+ 次。

这里是:

set $A = (void ***) &whateveritis
set $B = (void **) 0
set $WPN = 2
set $WP = 0
watch *$A
commands
  silent
  set $B = *$A
  if $WP != 0
    delete $WP
    set $WP = 0
  end
  if $B != (void *) 0
    watch *$B
    commands
      silent
      if *$B == magicalcorruptedvalue
        where
      else
        continue
      end
    end
    set $WP = $WPN++
  end
  continue
end

这会在 上设置一个观察点A,删除前一个上存在的任何以前的手表*A(最终将设置为B),然后将手表设置为当前的*A。手表总是在寻找magiccorruptedvalue,尽管在我的情况下B,它存储时的任何更改都是*A错误的,所以我省略了整个部分。

注意 $WPN 是下一个断点的编号。请注意由于临时隐式断点(例如通过start.

这应该可行,但请注意,在我的情况下,该程序是如此陷入困境,以至于它从未进入损坏的部分,因此观察点B从未被触发。YMMV。

回到现实世界,没有人用 gdb 做过如此复杂的事情。这里的教训是:(1)了解那里有哪些工具。Valgrind 很棒,我完全不确定任何 C 程序员,包括我自己,在没有它的情况下是如何应对的。(2) 仔细考虑问题域及其与您尝试使用的工具的关系。如果该工具不适合,请使用或编写其他内容。不要让语言欺骗你:仅仅因为你在“调试”并不意味着你应该用“调试器”来做。

于 2013-09-21T09:09:54.160 回答