展开操作期间遇到无效或未对齐的堆栈

An invalid or unaligned stack was encountered during an unwind operation

本文关键字:对齐 堆栈 无效 遇到 操作      更新时间:2023-10-16

我有一个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符号,但没有发现任何有用的东西——这是否表明异常解除正在进行中?

欢迎任何关于如何调试此问题的指针,或评论可能会打乱堆栈对齐的内容,因为我知道在这种情况下,由于涉及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()需要一个合适的帧指针,但没有得到?

不确定这是否有帮助,但我在与x64 Windows结合使用longjmp时遇到了类似的问题(没有VM)。

事实证明,在相同范围内的任何类型的对齐堆栈数据(与>=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

如果通过外部函数接口调用x64 MSVCRT的setjmp,需要注意的一点是,它需要一个未记录的第二个参数:紧接在调用之前的堆栈指针。这被存储在jmp_bufFrame成员中。如果不显式传递此参数,则Frame将变成RDX中发生的任何内容。longjmp调用RtlUnwindEx,后者检查目标Frame是否像有效的堆栈指针,如果不是,则引发STATUS_BAD_STACK异常。