C++ 中非常奇怪的堆栈溢出程序
我前段时间写了一个程序(Mac OS X、C++、SDL、FMOD),它的性能相当不错。但最近我想扩展它的功能并添加一些更多的代码。现在,当我运行它并尝试测试新功能时,程序因 SIGABRT 崩溃。
查看调试器,在函数堆栈上我看到:
- _kill
- Kill$UNIX2003
- raise
- __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),该语句永远不会在此模式下执行,程序不会崩溃!删除甚至无法执行的代码可以帮助解决这种情况!
现在,我不想删除这段代码,因为它用于我的程序的其他模式。那里工作得很好。那么有什么提示我可以在哪里搜索吗?这可能有什么问题?
I wrote a program some time ago (Mac OS X, C++, SDL, FMOD) and it perfomed rather good. But lately I wanted to extend its functionality and added some more code to it. And now, when I run it and try to test the new functionality, the program crashes with SIGABRT.
Looking into debugger, on function stack I see:
- _kill
- kill$UNIX2003
- raise
- __abort
- __stack_chk_fail
- odtworz <-- my function that was was modified
As far as I know, "__stack_chk_fail" indicates a stack overflow. But that's not the weirdest thing about it. In this function "odtworz", I have some code like this:
...
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 is a global variable and is set to value "2" in a function before. And now imagine - if I delete the third if statement (mode == 3) which never gets executed in this mode, the program doesn't crash! Deleting code that doesn't even get to be executed helps the situation!
Now, I don't want to delete this code because it's for other mode of my program. And it works fine there. So any hints where I can search? What could be possibly wrong with this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这不是堆栈溢出错误。当检测到堆栈帧损坏时,调用 __stack_chk_fail。破坏堆栈的传统方法是缓冲区溢出。导致它的代码不在您的代码片段中,而是在点中。
使用注释中的代码更新问题后: strcpy 和 sprintf 调用都是堆栈损坏的绝佳候选者。我在原来的答案中提到的缓冲区溢出问题。猜测一下:现在PiesnPlik看起来非常很小。 sprintf() 函数会向缓冲区写入过多的字符并覆盖“金丝雀”。当金丝雀被踩到时,运行时会吹口哨:)
您可以使数组更大。这不是真正的解决方案,请使用这些函数的安全替代方案,例如 snprintf()。我将避免提及 strncpy()。
It is not a stack overflow error. __stack_chk_fail is called when stack frame corruption is detected. The traditional way to smash the stack is a buffer overflow. The code that causes it is not in your snippet, it is in the dots.
After updating the question with code from a comment: both the strcpy and the sprintf calls are excellent candidates for stack corruption. The buffer overflow problem I mentioned in my original answer. Taking a guess: nowyPiesnPlik looks very small. The sprintf() function will write too many characters to the buffer and overwrite the "canary". When the canary gets stomped on, the runtime will whistle fowl :)
You could make the array bigger. Not a real solution, use safe alternatives for these functions, like snprintf(). I'll avoid mentioning strncpy().
我遇到了一个非常类似的问题,代码在
__stack_chk_fail
上崩溃。就我而言,上面推荐的解决方案是摆脱
sprintf()
。I experienced a very similar issue, code crashes on
__stack_chk_fail
.In my case, the solution as recommended above was to get rid of
sprintf()
.找到了!
罪魁祸首是在我给出的代码之前,但汉斯·帕桑特给了我一个线索,告诉我该看什么。它看起来像这样:
所以,我今天添加了第三个 if which user“piesnPlik”变量。但“nazwaNagraniaMP3”比复制到那里的其他两个变量长,因此它损坏了堆栈。但令人难以置信的是,它之后能够与所有 SDL 内容一起工作,但在从函数返回后却崩溃了。
感谢大家的建议!
Found it!
The culrpit was before code that I given, but Hans Passant gave me a clue what to look. It looked like this:
So, I added today the third if which user "piesnPlik" variable. But "nazwaNagraniaMP3" was longer than the two other variables that were copied there, so it corrupted the stack. But it's unbelievable that it managed to work with all SDL stuff after, only to crash after returning from the function.
Thanks all for Your suggestions!
一点也不奇怪。当涉及到堆栈溢出或堆损坏时,您应该预料到会很奇怪。堆栈指针、程序计数器或其他程序状态已损坏,因此调试器或跟踪工具无法准确报告崩溃时程序所在的位置。该错误可能位于代码中的其他位置,远离您发布的代码片段。从最近修改的代码开始。
编辑:您已经自己编写了一个很好的堆栈损坏示例,正如您后来发现的那样。无论如何,这是一个:
Not strange at all. When it comes to stack overflows or heap corruption, you should expect strange. The stack pointer, program counter, or other program state has been corrupted, so the debugger or trace tool can not accurately report where the program was at the time of the crash. The bug is likely elsewhere in your code, far away from the snippet you posted. Start with the most recently modified code.
Edit: You've already written a nice example of stack corruption yourself, as you've since discovered. Here's one anyway: