c++ - 抛出对齐类型时出现 Clang 运行时错误。编译器错误?

标签 c++ clang x86-64 memory-alignment

我有一个用 __attribute__((aligned(16))) 声明的类型。在 x86_64 上的 OS X 上使用 clang 构建时,以下代码在尝试 throw 包含此类型的值时会导致 GP 错误。出现此错误是因为编译器生成了一个 128 位移动指令,该指令必须在 16 字节边界上对齐,但地址未正确对齐。

这是一个重现问题的程序:

#include <stdint.h>
#include <stdio.h>

struct __attribute__((aligned(16))) int128 {
    uint64_t w[2];
};

int main()
{
    try {
        int128 x;
        throw x;
    } catch (int128 &e) {
        printf("%p %lu\n", &e, sizeof(e));
    }
}

以及用->标出故障位置的反汇编:

a.out`main:
    0x100000db0 <+0>:   pushq  %rbp
    0x100000db1 <+1>:   movq   %rsp, %rbp
    0x100000db4 <+4>:   subq   $0x40, %rsp
    0x100000db8 <+8>:   movl   $0x10, %eax
    0x100000dbd <+13>:  movl   %eax, %edi
    0x100000dbf <+15>:  callq  0x100000e8c               ; symbol stub for: __cxa_allocate_exception
    0x100000dc4 <+20>:  movaps -0x10(%rbp), %xmm0
->  0x100000dc8 <+24>:  movaps %xmm0, (%rax)
    0x100000dcb <+27>:  movq   0x23e(%rip), %rsi         ; (void *)0x0000000100001058
    0x100000dd2 <+34>:  xorl   %ecx, %ecx
    0x100000dd4 <+36>:  movl   %ecx, %edx
    0x100000dd6 <+38>:  movq   %rax, %rdi
    0x100000dd9 <+41>:  callq  0x100000e9e               ; symbol stub for: __cxa_throw

当前寄存器:

(lldb) register read rax
       rax = 0x0000000100905b08

看起来正在发生的事情是 __cxa_allocate_exception 函数不知道它为其分配存储的类型的对齐要求。在我的系统上,它恰好分配了一个以 8 结尾的地址,因此不是 16 字节对齐的。当 movaps 指令尝试将数据移动到该内存位置时,由于未对齐访问,CPU 会出现故障。

编译器信息(clang 来自 Xcode 6.3.2):

$ clang --version
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix

这是编译器错误吗?有什么办法可以解决这个问题?

更新:我已将此提交到 LLVM 错误数据库:https://llvm.org/bugs/show_bug.cgi?id=23868

最佳答案

进一步研究一下,似乎 __cxa_allocate_exception 基本上从未定义为理解对齐(对于 Clang 或 GCC),因此抛出对齐的对象基本上属于 UB(好吧,对齐是一个编译器- 无论如何特定的扩展名......)。它似乎保证的唯一对齐方式是 8 字节,因为这是任何内置类型 (double) 所需的最大对齐方式。

我能想到的最简单的解决方法就是在 throw 中使用未对齐的类型:

struct unaligned_int128 {
    uint64_t w[2];
    unaligned_int128(const int128 &x) { w[0] = x.w[0]; w[1] = x.w[1]; }
};

int main()
{
    try {
        int128 x;
        throw unaligned_int128(x);
    } catch (unaligned_int128 &e) {
        printf("%p %lu\n", &e, sizeof(e));
    }
}

关于c++ - 抛出对齐类型时出现 Clang 运行时错误。编译器错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30885997/

相关文章:

c++ - Clang:类中定义的友元函数

c++ - 如何设置 CMake 与 clang 交叉编译 Windows 上嵌入的 ARM?

c++ - Clang-Tidy 找不到我的头文件

c++ - 编译器在这里做什么,允许通过很少的实际比较来完成许多值的比较?

c++ - 如何做类似 "is_atomically_assignable"的事情?

c++ - 测试C++代码的性能

c++ - 如何防止在加载程序中重新创建页面?

assembly - 用于 C 语言的完整 x86/x64 JIT 汇编程序

c++ - CRT库类型

c++ - 在 C++ 的方法内部创建的对象实例的持久性