数据类型未对齐异常win32示例

时间:2018-11-11 20:42:26

标签: c++ winapi memory-alignment seh

有人可以在c ++上显示一个简单的示例,这会导致数据类型未对齐异常吗?我想看一个不使用RaiseException函数的示例。

3 个答案:

答案 0 :(得分:1)

在最新版本的MSVC中,这已经变得更加困难,因为它们不再遵守诸如_mm_load_ps_mm_store_ps之类的对齐内在函数,它们就像您要求非对齐版本一样被编译。但是流负载只有一个对齐的版本,因此我们可以在此处使用它来强制它在未对齐的地址上失败。例如这样的

__m128i test()
{
    char buffer[17];
    __m128i a = _mm_stream_load_si128((__m128i*)buffer);
    __m128i b = _mm_stream_load_si128((__m128i*)(buffer + 1));
    return _mm_or_si128(a, b);
}

有两个负载,每个负载相隔1个字节,地址不能两次对齐,因此失败。实际的异常将显示为“访问冲突读取位置0xFFFFFFFF”。

答案 1 :(得分:0)

这不会引起异常,但是g ++和clang ++均会给出有关未对齐的错误消息。也许VS也一样。

#include <iostream>
#include <stdexcept>

struct example {
    uint64_t a;
    uint64_t b;
};

int main() {
    example A;
    A.a = 1;
    A.b = 2;
    example* B = (example*)((char*)&A+1);
    try {
        std::cout << B->a << "\n";
        std::cout << "no exception thrown\n";
    } catch(const std::exception& ex) {
        std::cout << "exception: " << ex.what() << "\n";
    }
}

示例输出:

test.cpp:15:25: runtime error: member access within misaligned address 0x7ffd3f7cbe21 for type 'struct example', which requires 8 byte alignment
0x7ffd3f7cbe21: note: pointer points here
 00 00 00  01 00 00 00 00 00 00 00  02 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 0f 40 00 00
              ^
144115188075855872
no exception thrown

答案 2 :(得分:0)

  

我想看看不使用RaiseException函数的示例。

没有使用RaiseException函数? 某人必须...因为要获得C ++构造(例如__try of SEH or try of C++ exceptions)可捕获的异常的唯一方法就是某个地方引发异常。

在硬件级别,x86处理器具有“对齐检查”(AC)标志。如果设置了该标志,则在发生未对齐访问时,interrupt 17 is executed。但是在Windows中,您只能钩住此类中断if you are in kernel mode

如果您希望用户模式C ++程序接收与未对齐访问相关的异常-源自处理器观察未对齐访问的天生能力,则必须将其编写在设备驱动程序中。即便如此,获取异常也会涉及到对usermode的一些回调,从而导致异常的发生。

只是为了看看是否会因对齐错误而导致某种崩溃,我尝试将某些内联程序集从this answer改编为MSVC。 (MSVC的语法不同,但是我认为应该这样做……至少要进行后续的pushfd并使用提取的局部变量进行检查,这表明AC位确实会在此过程中发生变化):

#include <iostream>

int main() {
    __asm {
        pushfd
        mov eax, [esp]
        or eax, 0x40000
        mov [esp], eax
        popfd
    }

    char *data = new char[sizeof(int) + 1];
    int *p = reinterpret_cast<int*>(data + 1);
    *p = 304;
    std::cout << *p;
}

但是它似乎没有触发任何新的错误。我无法阅读cr0 register来查看是否设置了对齐掩码,它不会让我(mov eax, cr0导致“特权指令”错误)。而且我不知道Windows默认情况下会响应中断17,也许是无操作?或者,可能是在64位Windows版本上的x86程序没有注意这些,但是我无法执行64位指令,因为MSVC doesn't support inline assembly in 64-bit。 :-/

无论如何,重点仍然是:要使Win32 C ++程序通过对齐错误异常得到通知,则必须告诉您……并且Windows没有配置为对处理器本身注意到的对齐问题做出反应。因此,您的所有通知都将来自诸如编译器警告或usermode添加了对指针值本身的运行时检查之类的事情。