调试在C打一顿静态变量(GDB破?)(Debugging a clobbered static va

2019-09-16 09:30发布

我已经做了很多节目但在C并不多,而我调试需要咨询。 我有被约10-100秒的多线程程序(使用OS X 10.4并行线程)的执行之后打一顿一个静态变量(文件范围)。 我的代码看起来是这样的:

static float some_values[SIZE];
static int * addr;

addr指向有效存储器地址一会儿,然后被一些值(有时0,有时非零)打一顿,解除引用的时候从而引起段错误。 周围戳gdb我核实, addr是要布局在内存中后,立即some_values如人们所期望的,所以我的第一个猜想是,我使用了一个彻头彻尾的越界指数写信给some_values 。 然而,这是一个很小的文件,因此它很容易检查,这是没有问题的。

最明显的调试技术是设置观察点上的变量addr 。 但是这样做似乎创造不稳定和无法解释的行为gdb 。 观察点得到的第一项任务,以触发addr ; 再经过我继续执行,我立即得到一个荒谬的段错误在另一个线程...按说段错误就在程序的不同部分访问静态变量的地址! 但随后gdb让我读出和写入内存地址交互。

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x001d5bd0
0x0000678d in receive (arg=0x0) at mainloop.c:39
39          sample_buf_cleared ++;
(gdb) p &sample_buf_cleared
$17 = (int *) 0x1d5bd0
(gdb) p sample_buf_cleared
$18 = 1
(gdb) set sample_buf_cleared = 2
(gdb) 

gdb显然是混淆。 有谁知道为什么吗? 或者没有任何人有调试这个错误,而无需使用任何监视点建议?

Answer 1:

  1. 你可以把UINT的some_values和地址之间的数组,并确定您是否overruning some_values或者如果腐败会影响更多的地址,那么你首先想到的。 我会初始化填充到DEADBEEF或其他一些明显的模式,很容易区分的,不可能在节目中出现。 如果填充变化值,那么将它转换浮动,看看数字是有意义的浮动。

静态浮动some_values [SIZE]; 静态无符号整型填充[1024]; 静态INT *地址;

  1. 运行程序多次。 在每次运行禁用不同的线程,看到出现问题的时候消失。

  2. 设置程序进程关联到单个内核,然后尝试观察点。 您可能有更好的运气,如果你没有两个线程同时修改的值。 注意:此方法不排除这种情况的发生。 它可以更容易地在调试器赶上。



Answer 2:

static变量和多线程一般不混合。

没有看到你的代码(你应该包括你的线程代码),我的猜测是,你有两个线程同时写addr变量。 它不工作。

你要么需要:

  • 创建的单独实例addr为每个线程; 要么
  • 提供某种各地同步的addr停止两个线程在同一时间改变的值。


Answer 3:

尝试使用的valgrind; 我还没有试过在OS X Valgrind的,我不明白你的问题,但“尝试的valgrind”是我认为当你说“重挫”的第一件事情。



Answer 4:

有一两件事你可以尝试将创建一个单独的线程,其唯一目的是观看的价值addr ,而当它改变打破。 例如:

static int * volatile addr;  // volatile here is important, and must be after the *
void *addr_thread_proc(void *arg)
{
    while(1)
    {
        int *old_value = addr;
        while(addr == old_value) /* spin */;
        __asm__("int3");  // break the debugger, or raise SIGTRAP if no debugger
    }
}
...
pthread_t spin_thread;
pthread_create(&spin_thread, NULL, &addr_thread_proc, NULL);

然后,每当值addr发生变化时, int3指令将运行,这将打破调试器,停止所有线程。



Answer 5:

GDB经常怪异的行为与多线程程序。 另一种解决方案(如果你能负担得起的话)将是把printf()一切都结束了,试图赶在那里你的价值被打一顿的那一刻的场所。 不是很优雅,但有时​​是有效的。



Answer 6:

我没有做过的OSX任何调试,但我已经看到了GDB在Linux上相同的行为:程序崩溃,但GDB可以读取和写入该计划只是试图读取内存/写失败。

这并不一定意味着GDB是困惑; 而允许GDB读取经由ptrace的/写存储器内核(),它的下过程是不允许读或写。 IOW,这是一个(最近固定)内核错误。

不过,这听起来像GDB观察点工作不适合你无论出于何种原因。

你可以使用一种技术是mmap空间some_values ,而不是静态地为他们分配空间,安排阵列到一个页面边界结束 ,并安排接下来的页面是不可访问(通过mprotect )。

如果任何代码试图访问过去的结束some_values ,它会得到一个异常(实际上要设置一个不可写的“观察点”刚刚过去some_values )。



文章来源: Debugging a clobbered static variable in C (gdb broken?)