缓冲区溢出抛出返回地址
当我放入方法 A 时,它会导致缓冲区溢出,但当我返回时,它运行良好。 我认为 throw 将执行转移到调用者方法,因此它的地址应该与返回地址相同,但我显然错了。 有没有办法查看 Visual Studio 调试器中抛出的地址?
谢谢贝尔库斯
: 这是否意味着上层调用者方法的堆栈已损坏?例如,
Method A calls
Method B calls
Method C. Method C throws an exception
那么,有可能方法 C 的返回地址没问题,但方法 B 的返回地址已损坏,导致缓冲区溢出?我看到的是,如果没有抛出,我的应用程序运行良好,所以我认为方法 A、B 和 C 都有有效的返回地址。
When I throw in a method A, it causes buffer overrun but when I return, it runs fine.
I thought throw moves execution to the caller method so the address it goes to should be the same as return address, but i am obviuosly wrong.
Is there a way to see what address throw goes to in Visual Studio debugger?
Thank you
Berkus:
does this mean that stack of upper caller method is corrupted? So for example,
Method A calls
Method B calls
Method C. Method C throws an exception
Then, it is possible that Method C's return address is ok but Method B's return address is corrupted, causing buffer overrun? What I am seeing is that if there is no throw, my application runs fine, so I think Method A,B and C all have valid return addresses.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
返回地址和抛出的异常如何交互,具体取决于特定编译器如何实现异常处理的细节。要想非常肯定地说出任何事情,这里的人必须熟悉这些内部细节。
当然可以想象,缓冲区溢出可能会损坏仅由异常处理使用的数据(从而导致抛出失败),同时保持返回地址完好无损(从而允许正常返回成功)。但同样,这取决于编译器如何使用堆栈。 (在不同的编译器上,您可能会得到完全不同的症状)。腐败也可能导致了您尚未注意到的其他问题。或者这种损坏会在您下次更改代码后导致问题。如果堆栈(或 C++ 依赖的其他内存)被损坏,那么几乎任何事情都可能发生。
通过一些有根据的猜测工作或对编译器细节的了解,我确信有人最终可以回答有关返回地址以及抛出如何工作的具体问题。然而,我确实认为这些问题是错误的。
如果您确实知道缓冲区溢出,那么尝试回答这些问题就没有意义。只需修复超限即可。
如果您只是怀疑发生了溢出或试图追踪它是如何发生的,请尝试在调试器中单步执行代码并观察变量范围之外的内存更改。或者,也许,将您的函数更改为始终抛出,然后开始一一注释掉流程中的可疑部分。一旦抛出再次开始工作,您就可以仔细查看您上次评论的代码,因为问题很可能就在那里。如果这些建议没有帮助,那么我认为这里要问的真正问题是“如何追踪仅影响抛出异常的内存损坏?”。
Exactly how return addresses and thrown exceptions interact is left to the details of how your particular compiler implements exception handling. To say anything about it with much certainty, someone here would have to be familiar with those internal details.
It's certainly conceivable that a buffer overrun could corrupt data that is only used by the exception handling (thus causing a throw to fail) while leaving the return address intact (thus allowing a normal return to succeed). But again, that depends on how your compiler is making use of the stack. (On a different compiler you might get totally different symptoms). It's also possible that the corruption has caused other problems that you simply haven't noticed yet. Or that such corruption will cause problems in the future after the next time you change your code. If the stack (or other memory that C++ depends on) becomes corrupted, then just about anything could happen.
Wither some educated guess-work or knowledge of the compiler details, I'm sure someone could eventually answer the specific questions about return addresses and how throwing works. However, I really think these are the wrong questions to be asking.
If you actually know you have a buffer overrun, then there's no point in trying to answer these questions. Just fix the overrun.
If you only suspect you have an overrun or are trying to track down how it's happening, then try stepping through your code in the debugger and watch for changes to memory outside the bounds of your variables. Or perhaps, alter your function to always throw and then start commenting out suspicious parts of your process one by one. Once the throw starts working again, you can then take a closer look at the code you last commented since the problem is most likely there. If these suggestions don't help, then I think the real question to ask here is "How do I track down memory corruption that only affects throwing an exception?".
Throw 将展开堆栈,直到到达其中包含 catch 的函数。返回地址并不重要,因为如果需要, throw 可以上升几层堆栈帧。
Throw will unwind the stack, until it reaches the function with catch in it. The return address does not matter, as throw can go up several levels of stack frames if necessary.
在 C++ 中,如果没有 try/catch 块,则:
将终止应用程序。如果想避免终止,您的代码中必须有一个 try/catch 块。
In C++, if you have no try/catch block then this:
will terminate the application. You must have a try/catch block in your code if want to avoid termination.