我前段时间写了一个程序(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);
}
}
模式是一个全局变量,在之前的函数中设置为值“2”。现在想象一下 - 如果我删除了在此模式下永远不会执行的第三个if语句(mode == 3),程序不会崩溃!删除甚至无法执行的代码有助于这种情况!
现在,我不想删除此代码,因为它适用于我的程序的其他模式。它在那里工作得很好。那么我可以搜索的任何提示?这可能有什么问题?
答案 0 :(得分:16)
不堆栈溢出错误。检测到堆栈帧损坏时调用__stack_chk_fail。粉碎堆栈的传统方法是缓冲区溢出。导致它的代码不在您的代码段中,而是在点中。
使用评论中的代码更新问题后:strcpy和sprintf调用都是堆栈损坏的绝佳选择。我在原始答案中提到的缓冲区溢出问题。猜测:nowyPiesnPlik看起来非常小。 sprintf()函数会向缓冲区写入太多字符并覆盖“canary”。当金丝雀被踩到时,运行时会吹口哨:)
你可以让阵列更大。不是真正的解决方案,请使用snprintf()这些函数的安全替代方案。我会避免提及strncpy()。
答案 1 :(得分:2)
我遇到了一个非常类似的问题,__stack_chk_fail
上的代码崩溃了。
就我而言,上面推荐的解决方案是摆脱sprintf()
。
答案 2 :(得分:0)
一点也不奇怪。当谈到堆栈溢出或堆损坏时,你应该期待奇怪。堆栈指针,程序计数器或其他程序状态已损坏,因此调试器或跟踪工具无法准确报告崩溃时程序的位置。该错误可能在您的代码中的其他位置,远离您发布的代码段。从最近修改的代码开始。
编辑:您已经发现了自己编写好的堆栈损坏示例。无论如何这是一个:
void foo (){
int x[0];
x[-99] = -1;
}
答案 3 :(得分:0)
发现它!
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之后的东西,只是在从函数返回后崩溃。
感谢大家的建议!