[libc-commits] [libc] [libc] Add struct sockaddr_storage (on linux) (PR #192978)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Mon Apr 20 07:01:15 PDT 2026
https://github.com/labath created https://github.com/llvm/llvm-project/pull/192978
This deceptively simple patch has one catch. The POSIX standard states:
"""
When a pointer to a sockaddr_storage structure is converted to a pointer to a sockaddr structure, or vice versa, the ss_family member of the sockaddr_storage structure shall map onto the sa_family member of the sockaddr structure. When a pointer to a sockaddr_storage structure is converted to a pointer to a protocol-specific address structure, or vice versa, the ss_family member shall map onto a member of that structure that is of type sa_family_t that identifies the protocol's address family. When a pointer to a sockaddr structure is converted to a pointer to a protocol-specific address structure, or vice versa, the sa_family member shall map onto a member of that structure that is of type sa_family_t that identifies the protocol's address family. Additionally, the structures shall be defined in such a way that the compiler treats an access to the stored value of the sa_family_t member of any of these structures, via an lvalue expression whose type involves any other one of these structures, as permissible, despite the more restrictive expression rules on stored value access as stated in the ISO C standard.
...
Note that defining the sockaddr_storage and sockaddr structures using only mechanisms defined in early editions of the ISO C standard may produce aliasing diagnostics when applications use casting between pointers to the various socket address structures. Because of the large body of existing code utilizing sockets in a way that could trigger undefined behavior due to strict aliasing rules, this standard mandates that these structures can alias each other for accessing the sa_family_t member of the structures (or other members for protocol-specific structure references), so as to preserve well-defined semantics. An implementation's header files may need to use anonymous unions, or even an implementation-specific extension, to comply with the requirements of this standard.
"""
This is real problem w.r.t string aliasing rules, but this patch does not attempt to guarantee the above requirements -- because I haven't seen any other implementation do that. I'm also not sure that unions are sufficient to guarantee the above properties under a strict reading of the aliasing and "common initial sequence" rules. (If we wanted to go the non-standard extension route, we could slap may_alias on the relevant structures.)
>From 6886381e6bac3622b2d962fd34d25f7104600299 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 20 Apr 2026 13:03:57 +0000
Subject: [PATCH] [libc] Add struct sockaddr_storage (on linux)
This deceptively simple patch has one catch. The POSIX standard states:
"""
When a pointer to a sockaddr_storage structure is converted to a pointer
to a sockaddr structure, or vice versa, the ss_family member of the
sockaddr_storage structure shall map onto the sa_family member of the
sockaddr structure. When a pointer to a sockaddr_storage structure is
converted to a pointer to a protocol-specific address structure, or vice
versa, the ss_family member shall map onto a member of that structure
that is of type sa_family_t that identifies the protocol's address
family. When a pointer to a sockaddr structure is converted to a pointer
to a protocol-specific address structure, or vice versa, the sa_family
member shall map onto a member of that structure that is of type
sa_family_t that identifies the protocol's address family. Additionally,
the structures shall be defined in such a way that the compiler treats
an access to the stored value of the sa_family_t member of any of these
structures, via an lvalue expression whose type involves any other one
of these structures, as permissible, despite the more restrictive
expression rules on stored value access as stated in the ISO C standard.
...
Note that defining the sockaddr_storage and sockaddr structures using
only mechanisms defined in early editions of the ISO C standard may
produce aliasing diagnostics when applications use casting between
pointers to the various socket address structures. Because of the large
body of existing code utilizing sockets in a way that could trigger
undefined behavior due to strict aliasing rules, this standard mandates
that these structures can alias each other for accessing the sa_family_t
member of the structures (or other members for protocol-specific
structure references), so as to preserve well-defined semantics. An
implementation's header files may need to use anonymous unions, or even
an implementation-specific extension, to comply with the requirements of
this standard.
"""
This is real problem w.r.t string aliasing rules, but this patch does
not attempt to guarantee the above requirements -- because I haven't
seen any other implementation do that. I'm also not sure that unions are
sufficient to guarantee the above properties under a strict reading of
the aliasing and "common initial sequence" rules. (If we wanted to go
the non-standard extension route, we could slap may_alias on the
relevant structures.)
---
libc/hdr/types/CMakeLists.txt | 9 ++++++
libc/hdr/types/struct_sockaddr_storage.h | 21 ++++++++++++
libc/include/CMakeLists.txt | 1 +
libc/include/llvm-libc-types/CMakeLists.txt | 1 +
.../llvm-libc-types/struct_sockaddr_storage.h | 24 ++++++++++++++
libc/include/sys/socket.yaml | 1 +
libc/test/src/sys/socket/linux/CMakeLists.txt | 12 +++++++
.../socket/linux/sockaddr_storage_test.cpp | 32 +++++++++++++++++++
8 files changed, 101 insertions(+)
create mode 100644 libc/hdr/types/struct_sockaddr_storage.h
create mode 100644 libc/include/llvm-libc-types/struct_sockaddr_storage.h
create mode 100644 libc/test/src/sys/socket/linux/sockaddr_storage_test.cpp
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 3a88f781b4de0..40054b294a781 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -412,6 +412,15 @@ add_proxy_header_library(
libc.include.sys_socket
)
+add_proxy_header_library(
+ struct_sockaddr_storage
+ HDRS
+ struct_sockaddr_storage.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.struct_sockaddr_storage
+ libc.include.sys_socket
+)
+
add_proxy_header_library(
struct_sockaddr_un
HDRS
diff --git a/libc/hdr/types/struct_sockaddr_storage.h b/libc/hdr/types/struct_sockaddr_storage.h
new file mode 100644
index 0000000000000..c8559f2f84fb5
--- /dev/null
+++ b/libc/hdr/types/struct_sockaddr_storage.h
@@ -0,0 +1,21 @@
+//===-- Proxy for struct sockaddr_storage ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_SOCKADDR_STORAGE_H
+#define LLVM_LIBC_HDR_TYPES_STRUCT_SOCKADDR_STORAGE_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/struct_sockaddr_storage.h"
+
+#else
+
+#include <sys/socket.h>
+
+#endif // LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_STRUCT_SOCKADDR_STORAGE_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 0b8b17ee127be..67f8009d8b099 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -741,6 +741,7 @@ add_header_macro(
.llvm-libc-types.struct_linger
.llvm-libc-types.struct_msghdr
.llvm-libc-types.struct_sockaddr
+ .llvm-libc-types.struct_sockaddr_storage
)
add_header_macro(
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index e05e3fbc2d76f..6c2a001103250 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -196,6 +196,7 @@ add_header(sa_family_t HDR sa_family_t.h)
add_header(socklen_t HDR socklen_t.h)
add_header(struct_sockaddr_un HDR struct_sockaddr_un.h DEPENDS .sa_family_t)
add_header(struct_sockaddr HDR struct_sockaddr.h DEPENDS .sa_family_t)
+add_header(struct_sockaddr_storage HDR struct_sockaddr_storage.h DEPENDS .sa_family_t)
add_header(struct_iovec HDR struct_iovec.h DEPENDS .size_t)
add_header(struct_linger HDR struct_linger.h)
add_header(struct_msghdr HDR struct_msghdr.h DEPENDS .size_t .socklen_t .struct_iovec)
diff --git a/libc/include/llvm-libc-types/struct_sockaddr_storage.h b/libc/include/llvm-libc-types/struct_sockaddr_storage.h
new file mode 100644
index 0000000000000..f68bebb24cd8b
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_sockaddr_storage.h
@@ -0,0 +1,24 @@
+//===-- Definition of struct sockaddr_storage -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_STRUCT_SOCKADDR_STORAGE_H
+#define LLVM_LIBC_TYPES_STRUCT_SOCKADDR_STORAGE_H
+
+#include "sa_family_t.h"
+
+// A struct large (and aligned) enough to accomodate all supported
+// protocol-specific address structures.
+struct sockaddr_storage {
+ sa_family_t ss_family;
+ union {
+ char __ss_padding[128 - sizeof(sa_family_t)]; // Ensures size.
+ long __ss_align; // Ensures alignment.
+ };
+};
+
+#endif // LLVM_LIBC_TYPES_STRUCT_SOCKADDR_STORAGE_H
diff --git a/libc/include/sys/socket.yaml b/libc/include/sys/socket.yaml
index 28a81328a3559..41d8f8801a8a7 100644
--- a/libc/include/sys/socket.yaml
+++ b/libc/include/sys/socket.yaml
@@ -6,6 +6,7 @@ macros:
macro_header: sys-socket-macros.h
types:
- type_name: struct_sockaddr
+ - type_name: struct_sockaddr_storage
- type_name: socklen_t
- type_name: sa_family_t
- type_name: struct_msghdr
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index af0a46e9a06bb..77e3f114f1976 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -165,3 +165,15 @@ add_libc_unittest(
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
+
+add_libc_unittest(
+ sockaddr_storage_test
+ SUITE
+ libc_sys_socket_unittests
+ SRCS
+ sockaddr_storage_test.cpp
+ DEPENDS
+ libc.hdr.types.struct_sockaddr_storage
+ libc.hdr.types.struct_sockaddr_un
+ libc.src.string.memcpy
+)
diff --git a/libc/test/src/sys/socket/linux/sockaddr_storage_test.cpp b/libc/test/src/sys/socket/linux/sockaddr_storage_test.cpp
new file mode 100644
index 0000000000000..cf1d493360721
--- /dev/null
+++ b/libc/test/src/sys/socket/linux/sockaddr_storage_test.cpp
@@ -0,0 +1,32 @@
+//===-- Unittests for struct sockaddr_storage -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/types/struct_sockaddr_storage.h"
+#include "hdr/types/struct_sockaddr_un.h"
+#include "src/string/memcpy.h"
+
+#include "test/UnitTest/LibcTest.h"
+
+#include <sys/socket.h> // For AF_UNIX
+
+using LlvmLibcSockaddrStorageTest = LIBC_NAMESPACE::testing::Test;
+
+TEST_F(LlvmLibcSockaddrStorageTest, SizeAndAlignment) {
+ // TODO: Add other sockaddr_* types as they are defined.
+ static_assert(sizeof(struct sockaddr_un) <= sizeof(struct sockaddr_storage));
+ static_assert(alignof(struct sockaddr_un) <=
+ alignof(struct sockaddr_storage));
+}
+
+TEST_F(LlvmLibcSockaddrStorageTest, MemberAccess) {
+ struct sockaddr_un sun = {};
+ sun.sun_family = AF_UNIX;
+ struct sockaddr_storage ss;
+ LIBC_NAMESPACE::memcpy(&ss, &sun, sizeof(sun));
+ ASSERT_EQ(ss.ss_family, static_cast<sa_family_t>(AF_UNIX));
+}
More information about the libc-commits
mailing list