我一直在尝试找出我的代码中的间歇性崩溃错误(使用 setjmp),并将其缩小到:使用 /O2 编译时显示,使用 /O2 /Oy- 消失,即仅使用 omit 显示帧指针。
http://msdn.microsoft.com/en- us/library/2kxx5t2c(v=vs.80).aspx 建议 setjmp 需要帧指针。因此:
-
似乎当使用 setjmp 的程序使用 /O2 进行编译时,Visual C++ 会默默地生成导致间歇性堆栈损坏的代码。这是真的吗,还是我遗漏了什么?
-
在我看来,只有调用 setjmp 的函数才需要使用帧指针进行编译,程序的其余部分 - 甚至调用 longjmp 的函数 - 应该可以省略帧指针。这是真的吗?
编辑:我已经进一步缩小了范围。
在调用 setjmp 的函数上启用帧指针没有什么区别,但那是因为编译器已经这样做了,就像它应该做的那样,显然注意到它需要完成,并自动完成。
真正起作用的是在 main 上启用帧指针。这并不像听起来那么奇怪,因为崩溃是从 main 的返回中体现出来的。现在我想起来了,我可以在谷歌快速搜索 setjmp 用法中找到的所有示例,都在 main 中执行。也许微软编译器团队只是这样测试的。
这是使用它的惯用方法,也许最好的解决方法是我将 setjmp-using 函数内联到 main 中。
I've been trying to track down an intermittent crashing bug in my code (which uses setjmp), and narrowed it down to: shows up when compiling with /O2, goes away with /O2 /Oy-, i.e. only shows up with omit frame pointer.
http://msdn.microsoft.com/en-us/library/2kxx5t2c(v=vs.80).aspx suggests setjmp requires a frame pointer. Thus:
-
It seems that when a program that uses setjmp is compiled with /O2, Visual C++ silently generates code that causes intermittent stack corruption. Is this true, or am I missing something?
-
It seems to me that only the function that invokes setjmp should need to be compiled with frame pointer, the rest of the program - even the functions that call longjmp - should be okay to omit frame pointer. Is this true?
Edit: I've narrowed it down a little further.
Enabling frame pointer on the function that was calling setjmp made no difference, but that's because the compiler was doing that already, just as it should, obviously noticing it needed to be done, and doing it automatically.
What did make a difference was enabling frame pointer on main. That's not as bizarre as it sounds, since the crash was manifesting in return from main. Now that I think of it, all the examples I can find in a quick google search of setjmp usage, do it in main. Perhaps it happened that the Microsoft compiler team only tested it that way.
That being the idiomatic way to use it, perhaps the best workaround would be for me to just inline the setjmp-using function into main.
发布评论
评论(3)
好的,我已经发布了带有独立测试用例的错误报告,因此希望修复程序正在酝酿中:http://connect.microsoft.com/VisualStudio/feedback/details/666704/visual-c-generates-in Correct-code-with-omit-frame-pointer-and-setjmp
在同时,解决方法是要么不使用省略帧指针,要么将调用 setjmp 的代码放在 main 中,或者将调用 longjmp 的函数放在与调用 setjmp 相同的源文件中。
Okay, I've posted a bug report with a self-contained test case, so hopefully a fix is in the pipeline: http://connect.microsoft.com/VisualStudio/feedback/details/666704/visual-c-generates-incorrect-code-with-omit-frame-pointer-and-setjmp
In the meantime, the workaround is either don't use omit frame pointer, or put the code that calls setjmp in main, or put the function that calls longjmp in the same source file as the call to setjmp.
您能否指定有关崩溃本身的更多信息?我的意思是,编译器为
longjmp
生成的代码,崩溃是在longjmp
之后立即发生的,还是当您尝试访问自动变量时,或者当您尝试退出时发生的功能?我猜想target函数必须使用标准堆栈框架进行编译,对于使用
longjmp
的函数似乎没有合理的限制。Can you please specify more info about the crash itself? I mean, which code the compiler generated for the
longjmp
, does the crash happen immediately after thelongjmp
, or when you try to access automatic variables, or when you try to exit the function?I guess that the target function must be compiled with standard stack frame, there seems to be no reasonable limitation to the function that uses
longjmp
.setjmp 以多种不同的方式实现,但这可能与特定操作系统的程序集实现有关。
当使用 __stdcall 编译函数时,参数是相对于帧指针存储的。您的实现可能会访问相对于所述指针的 setjmp 参数,因此不必废弃多个寄存器来保存上下文(因为这会破坏 setjmp 的大部分意义);我好像记得setjmp在linux内核中是这样实现的。
当然,如果msvc不生成设置ebp的指令,那么这将不起作用并且肯定会导致崩溃。
setjmp is implemented in a lot of different ways, but this probably has something to do with the assembly implementation for your particular OS.
When a function is compiled using __stdcall, arguments are stored relative to the frame pointer. Your implementation may be accessing the arguments to setjmp relative to said pointer so it doesn't have to trash multiple registers saving the context to them (since this would ruin much of the point of setjmp); I seem to remember setjmp is implemented this way in the linux kernel.
Of course if msvc doesn't generate instructions to set ebp, then this won't work and will surely cause a crash.