为什么 glibc2.23 改变 struct sockaddr_storage?

Why glibc2.23 change struct sockaddr_storage?

我检查 git 日志为 https://patchwork.sourceware.org/patch/12453/。此修改似乎解决了特定平台上的问题。 但是我不明白为什么要在 struct sockaddr_storage 中交换 __ss_align 和 __ss_padding。 我现在正在开发的高通平台有很多类型转换如下。

struct sockaddr_storage prefix_addr

(struct sockaddr_in6 *)&(prefix_addr)->sin6_addr.s6_addr 

在我们的Cortex A7平台上,结构对齐方式如下:

glibc2.23 之前:

struct sockaddr_in6
{
    sin6_family;   //0th byte
    sin6_port;     //2nd byte
    sin6_flowinfo; //4th byte
    sin6_addr;     //8th byte
};


struct sockaddr_storage
{
    ss_family;    //0th byte
    __ss_align;   //4th byte
    __ss_padding; //8th byte
};

glibc2.23之后:

struct sockaddr_storage
{
    ss_family;    //0th byte
    __ss_padding; //2nd byte
    __ss_align;   //124th byte
};

glibc 更改了 struct sockaddr_storage,但 struct sockaddr_in6 未更改,因此此修改会在我们的平台上导致许多对齐问题,从而导致获取 IPV6 地址错误。

我不确定这是 glibc 中生成对齐警告的更改:此更改对您显示的源代码没有影响。

相反,我认为 Qualcomm 正在使用 clang,并且以 clang 4.x 开头,我看到了一个新的对齐警告生成 误报关于对齐的警告,具体取决于您编写代码的方式:-Waddress-of-packed-member.

您应该检查您使用的 clang 版本是否已更改,因为 glibc 已更改。如果是这种情况,这肯定可以解释你的问题。

使用临时变量使这些警告消失。

而不是像这样打电话:

my_function(((struct sockaddr_in6 *)&prefix_addr)->sin6_addr.s6_addr)

随便写:

struct sockaddr_in6 p = *(struct sockaddr_in6 *) &prefix_addr;
my_function(p.sin6_addr.s6_addr);

这可以避免对齐警告。

请参考Florian的回复:

On 09/01/2017 12:07 PM, honan li wrote:

define SASTORAGE_DATA(addr) (addr).__ss_padding

typedef struct qcmap_cm_nl_prefix_info_s { boolean prefix_info_valid; unsigned char prefix_len; unsigned int mtu; struct sockaddr_storage prefix_addr; struct ifa_cacheinfo cache_info; } qcmap_cm_nl_prefix_info_t;

void QCMAP_Backhaul::GetIPV6PrefixInfo(char *devname, qcmap_cm_nl_prefix_info_t *ipv6_prefix_info) { struct sockaddr_in6 *sin6 = NULL;

...

sin6 = (struct sockaddr_in6 *)&ipv6_prefix_info->prefix_addr; memcpy(SASTORAGE_DATA(ipv6_prefix_info->prefix_addr), RTA_DATA(rta), sizeof(sin6->sin6_addr)); ... }

目前在此处公开可用:

https://github.com/Bigcountry907/HTC_a13_vzw_Kernel/blob/master/vendor/qcom/proprietary/data/mobileap_v2/server/src/QCMAP_ConnectionManager.cpp#L3658

我希望应用程序做这样的事情:

结构sockaddr_in6sin6; memset (&sin6, 0, sizeof (sin6));
sin6.sin6_family = AF_INET6; memcpy (&sin6.sin6_addr, RTA_DATA (rta), sizeof (sin6.sin6_addr));内存文件 (&ipv6_prefix_info->prefix_addr, &sin6, sizeof (sin6));

这避免了任何别名问题和对内部结构的依赖 struct sockaddr_storage (这只是作为一种分配一个 具有足够大小和对齐方式的通用结构 sockaddr)。它也是 初始化套接字地址的其他组件(例如 端口号和流标签)。

谢谢,弗洛里安

另请参阅: https://books.google.com.hk/books?id=ptSC4LpwGA0C&pg=PA72&lpg=PA72&dq=alignment+sufficient&source=bl&ots=Kt0BQhjiMt&sig=HTUbm2bzVNSoMxNX98EMzORFc30&hl=zh-CN&sa=X&ved=0ahUKEwiP78iMoovWAhVLipQKHYFdCxcQ6AEIQzAF#v=onepage&q=alignment%20sufficient&f=false

结论是高通对sockaddr_storage的使用是不正确的。