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

时间:2014-10-28 09:41:59

标签: c++ com 64-bit virtualbox

我有一个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,因此无法提供精确的解决方案。

2 个答案:

答案 0 :(得分:2)

我最近遇到了这个令人困惑的问题。

我知道它只是在我从静态C / C ++运行时切换到DLL版本后才开始发生,所以这可能意味着静态版本没有进行堆栈展开。

然后我跟踪了longjmp()的汇编代码,发现第一个条件分支之一在_JUMP_BUFFER.Frame上。

如果它为0,则恢复一堆寄存器并返回。

啊哈!因此,如果_JUMP_BUFFER.Frame = 0,则必须表示禁用展开。我试过了,确实解决了问题。

然后我尝试观察当setjmp()/ longjmp()对成功时Frame应该是什么。我经常发现frame = stack指针,但是当展开失败时,帧!= SP。所以我尝试将Frame设置为SP,这也消除了异常。

我不知道为什么会有效。我知道在SYSV x86-64 ABI中,帧指针是可选的。也许setjmp()需要一个合适的帧指针而不是一个?

答案 1 :(得分:0)

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

原来,在longdmp的同一范围内,任何类型的对齐堆栈数据(与> = 32byte对齐)都会导致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