2

Clang 3.3 UBSan(未定义的行为清理程序)将以下代码标记为未对齐访问:

Address.cc:545:27: runtime error: load of misaligned address 0x60c00000a7df for type 'char *', which requires 8 byte alignment
0x60c00000a7df: note: pointer points here
 00 00 00 00 ef  a7 00 00 c0 60 00 00 00  00 00 00 00 00 00 00 c0  a8 64 0c 00 00 00 00 00  00 00 00
             ^
Address.cc:547:19: runtime error: reference binding to misaligned address 0x60c00000a7ef for type 'const struct in_addr', which requires 4 byte alignment
0x60c00000a7ef: note: pointer points here
 00 00 00 00 c0  a8 64 0c 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00
             ^

有问题的代码如下所示(忽略不正确的返回类型operator=):

bool
Ip::Address::operator =(const struct hostent &s)
{
    struct in_addr* ipv4 = NULL;

    switch (s.h_addrtype) {

    case AF_INET:
        // Line 545 below
        ipv4 = (in_addr*)(s.h_addr_list[0]);
        // Line 547 below
        operator=(*ipv4);
        break;
    ...
}

hostent结构:

struct hostent {
  char    *h_name;        /* official name of host */
  char    **h_aliases;    /* alias list */
  int     h_addrtype;     /* host address type */
  int     h_length;       /* length of address */
  char    **h_addr_list;  /* list of addresses */
}

这个squawk 是在Mac OS X 系统上产生的,我记得最近关于这是Xcode 或CFE Dev 邮件列表上的一个错误的讨论(但我现在找不到它)。

编辑:Sean McBride 很友好地提供了电子邮件的链接:-fcatch-undefined-behavior false positive with readdir()? 我不同意可以忽略它的说法(因为它来自操作系统而不是应用程序),特别是因为它可能导致SIGBUS错误。

如何重新对齐指针以清除 Clang 问题(h_addr给我带来最大的麻烦)?由于Apple的内部结构取决于它,它甚至可以完成吗?

4

3 回答 3

4

如果您有一个指向包含正确值的数据的指针,但偏移量不正确,您可能需要memcpy该数据。在你的情况下,ipv4变成一个堆栈变量(将被对齐),memcpys.h_addr_list[0]to ipv4

于 2013-09-16T07:03:35.887 回答
3

这是我最终在 Mac OS X 10.8.3 上修复两个未对齐指针的方法。(为了完整起见,Ubuntu 13 (x64) 上不存在这些问题。

void DoSomethingWithHostent(const hostent& he)
{
  // Mac OS X work around 1. Align hostent's h_addr.
  char** ip_addr;
  const void* ptr = (void*)&s.h_addr;
  memcpy(&ip_addr, ptr, sizeof(void*));

  // Mac OS X work around 2. Align in_addr's via memcpy below.
  typedef struct {
    union {
        in_addr ipv4;
        in6_addr ipv6;
    };
  } IN_ADDR_4or6;

  IN_ADDR_4or6 ipv4or6;

  // Back to business logic
  switch (s.h_addrtype) {

  case AF_INET:
    memcpy(&ipv4or6.ipv4, ip_addr, sizeof(ipv4or6.ipv4));
    DoSomethingWithInAddr(ipv4or6.ipv4);
    break;
  ...
  }
}
于 2013-09-17T00:53:00.910 回答
1

@jww 的修复对 C++ 非常有效,但是,对于 C,需要稍作修改:将 'in_addr' 更改为 'struct in_addr'。

我不得不移植类似的代码,为了比较这是之前的(使用未对齐的内存访问):

address.sin_addr.s_addr = ((struct in_addr *)(host->h_addr_list[0]))->s_addr;

之后,使用 memcpy 进行正确的内存对齐:

char **ip_addr;
memcpy(&ip_addr, &(host->h_addr_list[0]), sizeof(void *));
memcpy(&address.sin_addr.s_addr, ip_addr, sizeof(struct in_addr));
于 2017-06-12T03:13:35.663 回答