将围绕sockaddr_storage和sockaddr_in强制转换为严格别名

时间:2017-02-11 16:19:37

标签: c++ c linux sockets strict-aliasing

按照我之前的question,我对这段代码非常好奇 -

case AF_INET: 
    {
        struct sockaddr_in * tmp =
            reinterpret_cast<struct sockaddr_in *> (&addrStruct);
        tmp->sin_family = AF_INET;
        tmp->sin_port = htons(port);
        inet_pton(AF_INET, addr, tmp->sin_addr);
    }
    break;

在提出这个问题之前,我搜索过有关同一主题的SO,并对此主题进行了混合回答。例如,请参阅thisthisthis帖子,其中说使用此类代码在某种程度上是安全的。还有另一个post说使用工会来完成这样的任务,但是对接受的答案的评论再次不同。

微软的documentation在相同的结构上说 -

  

应用程序开发人员通常只使用SOCKADDR_STORAGE的ss_family成员。其余成员确保SOCKADDR_STORAGE可以包含IPv6或IPv4地址,并且适当填充结构以实现64位对齐。这种对齐使协议特定的套接字地址数据结构能够访问SOCKADDR_STORAGE结构中的字段而不会出现对齐问题。通过填充,SOCKADDR_STORAGE结构的长度为128个字节。

Opengroup的documentation个州 -

  

标题应定义sockaddr_storage结构。该结构应为:

     

足够大以容纳所有支持的协议特定地址结构

     

在适当的边界对齐,以便指向它的指针可以作为指向协议特定地址结构的指针,并用于访问这些结构的字段而不会出现对齐问题

socket的手册页也说同样的内容 -

  

此外,套接字API提供数据类型struct sockaddr_storage。此类型适用于容纳所有受支持的特定于域的套接字地址结构;它足够大并且正确对齐。 (特别是,它足以容纳IPv6套接字地址。)

我已经看到在野外用CC++种语言进行多次使用此类强制转换的实现,现在我不确定哪一个是正确的,因为有些帖子与之相矛盾以上声明 - thisthis

那么哪一个是填充sockaddr_storage结构的安全正确方法?这些指针转换是否安全?还是union method?我也知道getaddrinfo()调用,但对于刚刚填充结构的上述任务来说,这似乎有点复杂。还有一个recommended way with memcpy,这样安全吗?

1 个答案:

答案 0 :(得分:5)

是的,执行此操作是违规锯齿。所以不要。没有必要使用BrowserModule;这是一个历史错误。但是有一些安全的方法可以使用它:

  1. CommonModule。在这种情况下,指向内存在存储内容之前没有有效的类型。
  2. 作为工会的一部分,明确访问您想要的成员。但在这种情况下,只需将实际的sockaddr_storage类型(malloc(sizeof(struct sockaddr_storage))sockaddr以及in)放入联合而不是in6
  3. 当然,在现代编程中,您永远不需要创建un 类型的对象。只需使用sockaddr_storagestruct sockaddr_*来翻译字符串表示和getaddrinfo对象之间的地址,并将后者视为完全不透明的对象