在展开操作期间遇到无效或未对齐的堆栈
Posted
技术标签:
【中文标题】在展开操作期间遇到无效或未对齐的堆栈【英文标题】:An invalid or unaligned stack was encountered during an unwind operation 【发布时间】:2014-10-28 09:41:59 【问题描述】:我有一个 64 位程序,它与 VirtualBox COM 接口一起工作,并为虚拟机实现了一个前端。最近我开始对An invalid or unaligned stack was encountered during an unwind operation
异常感到奇怪,我想至少了解其原因。据我了解,堆栈需要 16 字节对齐,因此,我认为未对齐的堆栈指针可能会导致此问题。但问题是,由于我的程序所做的只是使用 ATL 中的 STDMETHOD
宏来实现几个 COM 接口,这些宏应该使用正确的调用约定,那么我怎么能搞砸堆栈呢?
以下是问题发生时的调用堆栈示例:
ntdll.dll!00007ffe679ac0b4() Unknown
ntdll.dll!00007ffe67913356() Unknown
msvcrt.dll!__longjmp_internal() Unknown
> VBoxREM.dll!000000006fb0f3c4() Unknown
我尝试获取 __longjmp_internal
符号,但没有发现任何有用的信息 - 这是否表明异常展开正在进行中?
欢迎任何有关如何调试此问题或 cmets 可能会破坏堆栈对齐的指针,因为我知道在这种情况下,由于涉及 VirtualBox,因此不可能给出准确的解决方案。
【问题讨论】:
我帮不上什么忙,但这是longjmp 无效比未对齐更有可能。您是否已确认对齐是问题所在,还是您只是在猜测?破坏堆栈的方法比世界上的程序员还要多。悬空或未初始化的指针和缓冲区溢出可能是最常见的。你犯了什么罪是无法猜测的。 @molbdnilo 我猜,因为如果我有一个悬空指针或内存溢出,我希望得到访问冲突或类似的东西,但我当然不能排除这些。我想我得做一些内存分析。 【参考方案1】:我最近遇到了这个莫名其妙的问题。
我知道它只是在我从静态 C/C++ 运行时切换到 DLL 版本后才开始发生,所以这可能意味着静态版本没有进行堆栈展开。
然后我跟踪 longjmp() 的汇编代码,发现第一个条件分支之一在 _JUMP_BUFFER.Frame 上。
如果为0,则恢复一堆寄存器并返回。
啊哈!所以这必须意味着如果_JUMP_BUFFER.Frame = 0,则禁用展开。我试过了,确实问题解决了。
然后我尝试观察当 setjmp()/longjmp() 对成功时 Frame 应该是什么。我通常发现,帧=堆栈指针,但是当展开失败时,帧!= SP。所以我尝试将 Frame 设置为 SP,这也消除了异常。
我不知道为什么会这样。我知道在 SYSV x86-64 ABI 中,帧指针是可选的。也许 setjmp() 需要一个适当的帧指针,但没有得到?
【讨论】:
哇哦,如果真的能做到这一点,那就太好了:) 谢谢,会检查一下。 “展开失败”究竟是什么意思——展开期间的异常?如果发生这种情况,我会异常终止,甚至无法返回跳转。 当我说“展开失败”时,我指的是 RtlUnwindEx() 中的“遇到无效或未对齐的堆栈”异常 啊,谢谢:) 我试着做一个最小的例子,但我看不出使用静态/动态运行时如何改变展开——在这两种情况下,堆栈中的所有对象都是在调用 @ 之前创建的987654321@ 已被销毁,但也许我遗漏了一些东西。 我也很难制作一个提交给 Microsoft 的最小示例。我的 longjmp() 失败的功能绝对是巨大的。我发现注释掉一些块会使问题消失,但找不到任何模式。 longjmp() 的堆栈展开不是强制性的,所以我认为静态库中的那个不会这样做。但我只是检查了一下,确实如此。您是否尝试在 setjmp() 之后将帧指针设置为 0? ((_JUMP_BUFFER *)&cpuState)->Frame = 0;【参考方案2】:不确定这是否有帮助,但我在使用 longjmp 和 x64 Windows 时遇到了类似的问题(没有虚拟机)。
事实证明,任何类型的对齐堆栈数据(对齐 >= 32 字节)在与 longjmp 相同的范围内都会导致 longjmp 在为 x64 编译时产生 0xC0000028。
#include <setjmpex.h>
void doThe_0xC0000028 ( )
jmp_buf jp;
if (!setjmp (jp))
// do some stuff ...
// ... then "revert" with longjmp.
longjmp (jp, 1);
// having any aligned data on stack (align > 16) in the same scope
// causes longjmp to go: 0xC0000028
//------------------------------------------------------------------
__declspec(align(32)) char buffer[12];
// just accessing buffer somehow - this is apparently needed to generate the faulty 0xC0000028
buffer[0];
我将其报告为 MSVC 错误: https://connect.microsoft.com/VisualStudio/feedback/details/3136150/64bit-longjmp-causing-0xc0000028-with-aligned-stack-data
【讨论】:
以上是关于在展开操作期间遇到无效或未对齐的堆栈的主要内容,如果未能解决你的问题,请参考以下文章
全局初始化失败:BadValue 无效或未设置用户区域设置。请确保正确设置 LANG 和/或 LC_* 环境变量