衆所周知,在所有的邏輯Bug中,野指針或者數組越界引起的Bug最難調,因爲暴露問題的地方與真正產生問題的地方往往不是在同一個地方,而且這種Bug往往具有隨機性,讓人頭痛。
調上述Bug的標準做法就是使用GDB的watch命令來監控內存變化,當watch的內存發生變化時,調試程序會停住,我們就知道是哪一步動了“奶酪”。
watch的使用也很簡單,如果有一個指針pTest指向一塊內存,則:
- watch pTest 監控pTest指針變量本身,如果pTest中存儲的內存地址發生變化,調試程序停住
- watch *pTest 監控pTest所指向的內存(*pTest本身就是一個地址數據),如果這塊內存發生變化,調試程序停住
其中watch *pTest的形式往往更常用
但在使用watch的時候會常常遇到如下問題:
https://stackoverflow.com/questions/4702638/gdb-watch-pointer-giving-too-many-h-w-watchpoints-error
(gdb) watch val_msgs[0]->val
Hardware watchpoint 2: this->val_msgs[0]->val
(gdb) c
Continuing.
pingCharmrun (ignored=0x7ffff73751c1) at machine.c:1151
1151 {
Current language: auto; currently c
(gdb) c
Continuing.
Warning:
Could not insert hardware watchpoint 2.
Could not insert hardware breakpoints:
You may have requested too many hardware breakpoints/watchpoints.
最後一行說設置了太多硬件斷點或者watch點,但實際上只設置了一個watch點,這其實是調試寄存器不夠用造成的,有如下兩種方案可以解決:
- 減少監控對象。我發現可以用全局指針來指向想監控的內存,然後watch全局指針,這樣就不會報錯,但是並不明白其中原理。
- 其實也不用這麼麻煩,標準解決方案是在GDB中:
set can-use-hw-watchpoints 0
就是將硬件watch點設置爲0,這樣GDB會使用軟件watch點,這當然比硬件watch點要慢,但是不影響GDB使用,更重要的是watch點可以放開用了。