一次手誤引出的bug

  在工做中寫了這樣一段代碼:函數

 1 struct xx_param {
 2        int index1;
 3        int index2;
 4 };
 5 
 6 //func1, func2, func3爲三個函數指針
 7 
 8 int init(a_func_t *func1, b_func_t *func2, c_func_t *func3, void *param)
 9 {
10        struct xx_param *p = (struct xx_param *)param;
11         func1(p->index1, p->index2);
12 }
13 
14 int prepare_init(int xx_index_1, int xx_index_2)
15 {
16         int err;
17         struct xx_param        xx;
18         
19        ......
20 
21         xx.index1 = xx_index1;
22         xx.index2 = xx_index2;
23 
24         if(init(func1, func2, func3, &xx_index1))
25                err = -xxx;
26 20        ......
27 
28         return err;
29 }

  很明顯這個錯誤很普通,就是第24行應該爲&xx,可是我手誤錯寫成了&xx_index1。可是編譯器不會報警,下面來講一下這個錯誤的神奇之處,在Debug下永遠是正確的,可是Release下永遠跑飛。下面來分析一下爲何:佈局

  在Debug模式下參數是由棧來傳遞的,那麼參數xx_index_1, xx_index_2在棧中的佈局 與 xx結構體變量在棧中的佈局徹底同樣,所以雖然我取錯了地址,可是根據&xx_index_1處獲得的地址來獲到xx_index1, xx_index_2,其實至關於將結構體變量xx賦值而後從&xx地址處取xx.index1,xx.index2變量(貌似還少了幾回內存拷貝,雖然他是一個bug, ^_&),所以在Debug模式下這斷代碼永遠是正確的。優化

  可是在Release下卻不正確,由於在VS下,O2的優化級別下xx_index_1, xx_index_2是由寄存器ecx, edx來傳遞的,xx_index_1, xx_index_2兩個變量的值不會所有在棧中分配(因爲對xx_index1進行取地址,所以會致使編譯器爲xx_index1分配內存,可是xx_index_2確不會分配內存),這樣從&xx地址去取數據時xx.index2變量取到的數據老是垃圾數據,所以軟件在Release下老是掛掉,但若是將優化關掉卻又能良好運行。
spa

  這個Bug很簡單,可是現象卻很詭異,所以感受值得一記。指針

相關文章
相關標籤/搜索