簡體   English   中英

C ++程序中非常奇怪的堆棧溢出

[英]VERY strange stack overflow in C++ program

我不久前寫了一個程序(Mac OS X,C ++,SDL,FMOD),它表現得相當不錯。 但最近我想擴展其功能並為其添加更多代碼。 現在,當我運行它並嘗試測試新功能時,程序會與SIGABRT崩潰。

查看調試器,在函數堆棧上我看到:

  • _殺
  • 殺$ UNIX2003
  • 提高
  • __abort
  • __stack_chk_fail
  • odtworz < - 我的功能被修改了

據我所知,“__ stack_chk_fail”表示堆棧溢出。 但這不是最奇怪的事情。 在這個函數“odtworz”中,我有一些像這樣的代碼:

...

koniec = 0;
while ( koniec == 0 ) {
    ...
    if (mode == 1) {
        ...
    }
    else if (mode == 2) {
        ...
    }
    else if (mode == 3) {
       piesniOrkiestrowe[0] = '\0'; 
       while ( piesniOrkiestrowe[0] == '\0' ) { 
           losowaPiesn(); 
           char * piesnOrkiestrowa = szukajPiesniOrkiestrowej(); 
           if ( piesnOrkiestrowa != NULL ) 
              strcpy(piesniOrkiestrowe, piesnOrkiestrowa); 
       } 
       char nowyPiesnPlik[25]; 
       sprintf(nowyPiesnPlik, "%sorch/%s", PIESNI_DIR.c_str(), piesniOrkiestrowe);
    }
}

mode是一個全局變量,在之前的函數中設置為值“2”。 現在想象一下 - 如果我刪除了在此模式下永遠不會執行的第三個if語句(mode == 3),程序不會崩潰! 刪除甚至無法執行的代碼有助於這種情況!

現在,我不想刪除此代碼,因為它適用於我的程序的其他模式。 它在那里工作得很好。 那么我可以搜索的任何提示? 這可能有什么問題?

不是堆棧溢出錯誤。 檢測到堆棧幀損壞時調用__stack_chk_fail。 粉碎堆棧的傳統方法是緩沖區溢出。 導致它的代碼不在您的代碼段中,而是在點中。


用注釋中的代碼更新問題后:strcpy和sprintf調用都是堆棧損壞的絕佳候選者。 我在原始答案中提到的緩沖區溢出問題。 以一個猜測:nowyPiesnPlik看起來非常小。 sprintf()函數會向緩沖區寫入太多字符並覆蓋“canary”。 當金絲雀被踩到時,運行時會吹口哨:)

你可以讓陣列更大。 不是真正的解決方案,請使用snprintf()這些函數的安全替代方案。 我會避免提到strncpy()。

我遇到了一個非常類似的問題,代碼崩潰在__stack_chk_fail 就我而言,上面推薦的解決方案是擺脫sprintf()

一點都不奇怪。 當談到堆棧溢出或堆損壞時,你應該期待奇怪。 堆棧指針,程序計數器或其他程序狀態已損壞,因此調試器或跟蹤工具無法准確報告崩潰時程序的位置。 該錯誤可能在您的代碼中的其他位置,遠離您發布的代碼段。 從最近修改的代碼開始。

編輯:您已經自己編寫了一個很好的堆棧損壞示例,正如您自己發現的那樣。 無論如何這是一個:

void foo (){ 
    int x[0];
    x[-99] = -1;
}

找到了!

culrpit在我給出的代碼之前,但Hans Passant給了我一個線索的樣子。 它看起來像這樣:

char piesnPlik[25];
if ( mode == TRYB_PIANINO )
    sprintf(piesnPlik, "%spiano/%s.mp3", PIESNI_DIR.c_str(), wybranaPiesn);
else if ( tryb == TRYB_ORKIESTRA )
    sprintf(piesnPlik, "%sorch/%s", PIESNI_DIR.c_str(), piesniOrkiestrowe);
else if ( tryb == TRYB_NAGRANIE )
    sprintf(piesnPlik, "%s/%s", NAGRANIA_DIR.c_str(), nazwaNagraniaMP3);

所以,我今天添加了第三個用戶“piesnPlik”變量。 但是“nazwaNagraniaMP3”比那里復制的其他兩個變量要長,所以它破壞了堆棧。 但令人難以置信的是,它成功地使用了所有SDL之后的東西,只是在從函數返回后崩潰了。

謝謝大家的建議!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM