是否由于铸造未定义行为导致负载未对齐?

Is a misaligned load due to a cast undefined behavior?

是否由于 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++;

  ...
}

相关,但我不相信回答了上面的问题:

我认为您的具体问题的答案是 "yes"——虽然我不确定它是否特定于转换本身,但通常是未对齐的指针。 buf_xor() 的内部代码在我看来基本没问题,所以我会看看传入的地址是什么。

在我看来,您不想使用未对齐的地址调用 buf_xor()。如果不是这样(如果你在任何地方调用 but_xor() 并使用对齐的地址),那么我会确保 uintptr_t 被定义为相同的东西(特别是 64 位宽,基于在你的输出中)编译 buf_xor() 的位置,以及调用它的位置。

最后一个个人意见是,因为您的 buf_xor() 实现需要对齐指针作为某些 processor/compiler 实现的参数,您可能可以通过更改签名来反映这一点,从而避免将来出现一些麻烦(将 void * 更改为 uintptr_t *)——或更改实现本身以优雅地处理,'manually',在所有体系结构上使用未对齐的地址。

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

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned [...] for the referenced type, the behavior is undefined.

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

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

如果出于性能原因应复制 uintptr_t 大小的块,可以使用 unsigned char 直到地址正确对齐,然后再循环复制 uintptr_t。这应该通过联合或通过 memcpy 来避免别名问题(如果大小不变,Gcc 可以优化 memcpy 调用)。可能需要再次通过 unsigned char 复制最后一个字节以避免越界访问(读取数组后的 sizeof(uintptr_t)-1 字节不会导致问题(Glibc 在多个地方这样做),但是通过 dst 写入可能会写入另一个对象)。它可能有助于 restrict-限定使用的指针。