[libc-commits] [libc] [libc] Add struct sockaddr_storage (on linux) (PR #192978)

Pavel Labath via libc-commits libc-commits at lists.llvm.org
Wed Apr 22 01:11:26 PDT 2026


https://github.com/labath updated https://github.com/llvm/llvm-project/pull/192978

>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 1/3] [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));
+}

>From 5b35b3db84dd7b239c73d2067f82d50cd9781c2b Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 22 Apr 2026 07:43:00 +0000
Subject: [PATCH 2/3] use may_alias

---
 .../include/llvm-libc-types/struct_sockaddr.h |  2 +-
 .../llvm-libc-types/struct_sockaddr_storage.h |  2 +-
 .../llvm-libc-types/struct_sockaddr_un.h      |  2 +-
 libc/test/src/sys/socket/linux/CMakeLists.txt |  2 +-
 .../socket/linux/sockaddr_storage_helper.cpp  | 26 +++++++++++++++++++
 .../socket/linux/sockaddr_storage_test.cpp    | 13 +++++-----
 6 files changed, 37 insertions(+), 10 deletions(-)
 create mode 100644 libc/test/src/sys/socket/linux/sockaddr_storage_helper.cpp

diff --git a/libc/include/llvm-libc-types/struct_sockaddr.h b/libc/include/llvm-libc-types/struct_sockaddr.h
index b7579e9c6ba73..d85f0919259cd 100644
--- a/libc/include/llvm-libc-types/struct_sockaddr.h
+++ b/libc/include/llvm-libc-types/struct_sockaddr.h
@@ -11,7 +11,7 @@
 
 #include "sa_family_t.h"
 
-struct sockaddr {
+struct __attribute__((may_alias)) sockaddr {
   sa_family_t sa_family;
   // sa_data is a variable length array. It is provided with a length of one
   // here as a placeholder.
diff --git a/libc/include/llvm-libc-types/struct_sockaddr_storage.h b/libc/include/llvm-libc-types/struct_sockaddr_storage.h
index f68bebb24cd8b..ae59c474a0a8b 100644
--- a/libc/include/llvm-libc-types/struct_sockaddr_storage.h
+++ b/libc/include/llvm-libc-types/struct_sockaddr_storage.h
@@ -13,7 +13,7 @@
 
 // A struct large (and aligned) enough to accomodate all supported
 // protocol-specific address structures.
-struct sockaddr_storage {
+struct __attribute__((may_alias)) sockaddr_storage {
   sa_family_t ss_family;
   union {
     char __ss_padding[128 - sizeof(sa_family_t)]; // Ensures size.
diff --git a/libc/include/llvm-libc-types/struct_sockaddr_un.h b/libc/include/llvm-libc-types/struct_sockaddr_un.h
index 5ed31a49ebb51..0c9f81427d847 100644
--- a/libc/include/llvm-libc-types/struct_sockaddr_un.h
+++ b/libc/include/llvm-libc-types/struct_sockaddr_un.h
@@ -14,7 +14,7 @@
 // This is the sockaddr specialization for AF_UNIX or AF_LOCAL sockets, as
 // defined by posix.
 
-struct sockaddr_un {
+struct __attribute__((may_alias)) sockaddr_un {
   sa_family_t sun_family; /* AF_UNIX */
   char sun_path[108];     /* Pathname */
 };
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index daf95ccdd9ba6..f4bd361258e51 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -194,8 +194,8 @@ add_libc_unittest(
     libc_sys_socket_unittests
   SRCS
     sockaddr_storage_test.cpp
+    sockaddr_storage_helper.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_helper.cpp b/libc/test/src/sys/socket/linux/sockaddr_storage_helper.cpp
new file mode 100644
index 0000000000000..4735c0f3cc6cf
--- /dev/null
+++ b/libc/test/src/sys/socket/linux/sockaddr_storage_helper.cpp
@@ -0,0 +1,26 @@
+//===-- Helpers for the struct sockaddr_storage test ----------------------===//
+//
+// 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/sys_socket_macros.h"
+#include "hdr/types/struct_sockaddr_storage.h"
+#include "hdr/types/struct_sockaddr_un.h"
+#include "include/llvm-libc-types/sa_family_t.h"
+
+// POSIX requires (and many applications make use of this) the ability to cast
+// one sockaddr pointer to another. This verifies that the compiler does not
+// assume the two pointers do not point to the same object (alias). It is in a
+// different compile unit to prevent the compiler from noticing (at least
+// without LTO) that the two variables point to the same object. Noticing that
+// wouldn't cause the test to fail, but it might cause it to not test the
+// desired property.
+sa_family_t test_sockaddr_aliasing(struct sockaddr_storage *ss,
+                                   struct sockaddr_un *sun) {
+  ss->ss_family = AF_UNSPEC;
+  sun->sun_family = AF_UNIX;
+  return ss->ss_family == static_cast<sa_family_t>(AF_UNIX);
+}
diff --git a/libc/test/src/sys/socket/linux/sockaddr_storage_test.cpp b/libc/test/src/sys/socket/linux/sockaddr_storage_test.cpp
index cf1d493360721..d417a3535f58d 100644
--- a/libc/test/src/sys/socket/linux/sockaddr_storage_test.cpp
+++ b/libc/test/src/sys/socket/linux/sockaddr_storage_test.cpp
@@ -8,7 +8,6 @@
 
 #include "hdr/types/struct_sockaddr_storage.h"
 #include "hdr/types/struct_sockaddr_un.h"
-#include "src/string/memcpy.h"
 
 #include "test/UnitTest/LibcTest.h"
 
@@ -16,6 +15,9 @@
 
 using LlvmLibcSockaddrStorageTest = LIBC_NAMESPACE::testing::Test;
 
+sa_family_t test_sockaddr_aliasing(struct sockaddr_storage *ss,
+                                   struct sockaddr_un *sun);
+
 TEST_F(LlvmLibcSockaddrStorageTest, SizeAndAlignment) {
   // TODO: Add other sockaddr_* types as they are defined.
   static_assert(sizeof(struct sockaddr_un) <= sizeof(struct sockaddr_storage));
@@ -24,9 +26,8 @@ TEST_F(LlvmLibcSockaddrStorageTest, SizeAndAlignment) {
 }
 
 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));
+  struct sockaddr_storage ss = {};
+  auto *sun = reinterpret_cast<struct sockaddr_un *>(&ss);
+  ASSERT_EQ(static_cast<sa_family_t>(AF_UNIX),
+            test_sockaddr_aliasing(&ss, sun));
 }

>From 2f4a37c177b6209ce470a5ef23546d014b38542e Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 22 Apr 2026 08:10:46 +0000
Subject: [PATCH 3/3] fix test (probably will not fix the bots)

---
 libc/test/src/sys/socket/linux/sockaddr_storage_helper.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/test/src/sys/socket/linux/sockaddr_storage_helper.cpp b/libc/test/src/sys/socket/linux/sockaddr_storage_helper.cpp
index 4735c0f3cc6cf..0c6d7a128fea0 100644
--- a/libc/test/src/sys/socket/linux/sockaddr_storage_helper.cpp
+++ b/libc/test/src/sys/socket/linux/sockaddr_storage_helper.cpp
@@ -22,5 +22,5 @@ sa_family_t test_sockaddr_aliasing(struct sockaddr_storage *ss,
                                    struct sockaddr_un *sun) {
   ss->ss_family = AF_UNSPEC;
   sun->sun_family = AF_UNIX;
-  return ss->ss_family == static_cast<sa_family_t>(AF_UNIX);
+  return ss->ss_family;
 }



More information about the libc-commits mailing list