我有一个 64 位程序,可与 VirtualBox COM 接口(interface)配合使用并实现虚拟机的前端。最近,我开始遇到奇怪的在展开操作期间遇到无效或未对齐的堆栈
异常,我想至少了解其原因。据我所知,堆栈需要 16 字节对齐,因此,我认为未对齐的堆栈指针可能会导致这种情况。但问题是,由于我的程序所做的只是使用 ATL 中的 STDMETHOD
宏实现几个 COM 接口(interface),而这些宏应该使用正确的调用约定,那么我怎么会弄乱堆栈呢?
以下是出现问题时的调用堆栈示例:
ntdll.dll!00007ffe679ac0b4() Unknown
ntdll.dll!00007ffe67913356() Unknown
msvcrt.dll!__longjmp_internal() Unknown
> VBoxREM.dll!000000006fb0f3c4() Unknown
我尝试搜索 __longjmp_internal
符号,但没有找到任何有用的东西 - 它是否表明异常展开正在进行中?
欢迎任何有关如何调试此问题的指针或可能会扰乱堆栈对齐的评论,因为我知道在这种情况下,由于涉及 VirtualBox,因此不可能给出准确的解决方案。
最佳答案
我最近遇到了这个令人困惑的问题。
我知道它只是在我从静态 C/C++ 运行时切换到 DLL 版本后才开始发生,因此这可能意味着静态版本没有执行堆栈展开。
然后,我跟踪了 longjmp() 的汇编代码,并注意到第一个条件分支之一位于 _JUMP_BUFFER.Frame 上。
如果是0,则恢复一堆寄存器并返回。
啊哈!所以这必然意味着如果 _JUMP_BUFFER.Frame = 0,则展开被禁用。我尝试了一下,确实问题解决了。
然后,我尝试观察 setjmp()/longjmp() 对成功时的 Frame 应该是什么。我发现通常,frame = 堆栈指针,但是当展开失败时,frame != SP。所以我尝试将 Frame 设置为 SP,这也消除了异常。
我不知道为什么会这样。我知道在 SYSV x86-64 ABI 中,帧指针是可选的。也许 setjmp() 需要一个适当的帧指针但没有得到一个?
关于c++ - 展开操作期间遇到无效或未对齐的堆栈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26605063/