是否由于未定义的行为造成错位负载?

是否由于void*未定义的行为导致错位负载?


以下是我对Clang及其消毒剂的看法:

 bufhelp.h:146:29: runtime error: load of misaligned address 0x7fff04fdd0e1 for type 'const uintptr_t' (aka 'const unsigned long'), which requires 8 byte alignment 0x7fff04fdd0e1: note: pointer points here 00 00 00 66 66 6f 6f 62 61 72 34 32 46 4f 4f 42 41 52 31 37 66 6f 6f 62 61 72 34 33 46 4f 4f 42 ^ 

这是演员阵容发挥作用的地方:

 buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len) { ... ldst = (uintptr_t *)(void *)dst; lsrc1 = (const uintptr_t *)(const void *)src1; lsrc2 = (const uintptr_t *)(const void *)src2; for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t)) *ldst++ = *lsrc1++ ^ *lsrc2++; ... } 

相关,但我不相信上述问题的答案:

  • 什么是错位指针?
  • 在C中输入punning和Unions
  • 使用void *键入punning而不破坏C99中的严格别名规则

转换为错误对齐的指针本身是未定义的,不仅是通过该指针的加载(C11(n1570)6.3.2.3 p7):

指向对象类型的指针可以转换为指向不同对象类型的指针。 如果结果指针未正确对齐引用类型[…],则行为未定义。

显示的代码也会破坏严格的别名,因为指向的对象不太可能被声明为uintptr_t (否则地址将正确对齐)。

为了符合标准,可以使用unsigned char

如果出于性能原因而复制uintptr_t -sized块,则可以使用unsigned char直到地址正确对齐,然后再复制uintptr_t循环。 这应该通过union或memcpy来完成,以避免出现混淆问题(如果大小不变,Gcc可以优化memcpy调用)。 可能需要再次通过unsigned char复制最后一个字节以避免越界访问(读取sizeof(uintptr_t)-1个字节超过数组不应该导致问题(Glibc在几个地方执行此操作),但写入通过dst可以写入另一个对象)。 它可能有助于restrict – 使用指针。

我认为你的具体问题的答案是“是” – 虽然我不确定它是否特定于演员本身,但总体来说是未对齐的指针。 buf_xor()内部的代码看起来对我来说很好,所以我将看一下传递的地址是什么。

它看起来像你不想用未对齐的地址调用buf_xor()。 如果那不是它(如果你用对齐的地址调用but_xor()),那么我要确保uintptr_t被定义为相同的东西(特别是64位宽,基于你的输出)其中buf_xor()编译,以及它被调用的地方。

最后一个个人观点是因为你的buf_xor()实现需要在一些处理器/编译器实现上将对齐的指针作为参数,你可以通过改变签名来反映这一点(将void void *改为uintptr_t *)来节省一些未来的麻烦 – 或者更改实现本身,以“手动”方式优雅地处理所有体系结构上的未对齐地址。