[英]VERY strange stack overflow in C++ program
我不久前寫了一個程序(Mac OS X,C ++,SDL,FMOD),它表現得相當不錯。 但最近我想擴展其功能並為其添加更多代碼。 現在,當我運行它並嘗試測試新功能時,程序會與SIGABRT崩潰。
查看調試器,在函數堆棧上我看到:
據我所知,“__ 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.