我已经做了很多节目但在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
显然是混淆。 有谁知道为什么吗? 或者没有任何人有调试这个错误,而无需使用任何监视点建议?
- 你可以把UINT的some_values和地址之间的数组,并确定您是否overruning some_values或者如果腐败会影响更多的地址,那么你首先想到的。 我会初始化填充到DEADBEEF或其他一些明显的模式,很容易区分的,不可能在节目中出现。 如果填充变化值,那么将它转换浮动,看看数字是有意义的浮动。
静态浮动some_values [SIZE]; 静态无符号整型填充[1024]; 静态INT *地址;
运行程序多次。 在每次运行禁用不同的线程,看到出现问题的时候消失。
设置程序进程关联到单个内核,然后尝试观察点。 您可能有更好的运气,如果你没有两个线程同时修改的值。 注意:此方法不排除这种情况的发生。 它可以更容易地在调试器赶上。
static
变量和多线程一般不混合。
没有看到你的代码(你应该包括你的线程代码),我的猜测是,你有两个线程同时写addr
变量。 它不工作。
你要么需要:
- 创建的单独实例
addr
为每个线程; 要么 - 提供某种各地同步的
addr
停止两个线程在同一时间改变的值。
尝试使用的valgrind; 我还没有试过在OS X Valgrind的,我不明白你的问题,但“尝试的valgrind”是我认为当你说“重挫”的第一件事情。
有一两件事你可以尝试将创建一个单独的线程,其唯一目的是观看的价值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
指令将运行,这将打破调试器,停止所有线程。
GDB经常怪异的行为与多线程程序。 另一种解决方案(如果你能负担得起的话)将是把printf()
一切都结束了,试图赶在那里你的价值被打一顿的那一刻的场所。 不是很优雅,但有时是有效的。
我没有做过的OSX任何调试,但我已经看到了GDB在Linux上相同的行为:程序崩溃,但GDB可以读取和写入该计划只是试图读取内存/写失败。
这并不一定意味着GDB是困惑; 而允许GDB读取经由ptrace的/写存储器内核(),它的下过程是不允许读或写。 IOW,这是一个(最近固定)内核错误。
不过,这听起来像GDB观察点工作不适合你无论出于何种原因。
你可以使用一种技术是mmap
空间some_values
,而不是静态地为他们分配空间,安排阵列到一个页面边界结束 ,并安排接下来的页面是不可访问(通过mprotect
)。
如果任何代码试图访问过去的结束some_values
,它会得到一个异常(实际上要设置一个不可写的“观察点”刚刚过去some_values
)。