[libc-commits] [libc] f3294c2 - [libc] Add socket test support library (#193207)

via libc-commits libc-commits at lists.llvm.org
Tue May 5 06:51:16 PDT 2026


Author: Pavel Labath
Date: 2026-05-05T13:51:10Z
New Revision: f3294c2338d27e2cd411fddcf1afd169d1996ccf

URL: https://github.com/llvm/llvm-project/commit/f3294c2338d27e2cd411fddcf1afd169d1996ccf
DIFF: https://github.com/llvm/llvm-project/commit/f3294c2338d27e2cd411fddcf1afd169d1996ccf.diff

LOG: [libc] Add socket test support library (#193207)

A couple of tests (and I plan to add a couple more) need to
create/compare unix domain socket addresses. This isn't completely
trivial due to the the interaction between the `addrlen` argument and
the terminating '\0', and the existing code doing that was subtly wrong
in some cases.

This patch centralizes the functions for these operations, reducing code
duplication and ensuring consistent (and correct) behavior everywhere.

Added: 
    libc/test/src/sys/socket/linux/socket_test_support.h

Modified: 
    libc/src/__support/CMakeLists.txt
    libc/src/__support/c_string.h
    libc/test/src/sys/socket/linux/CMakeLists.txt
    libc/test/src/sys/socket/linux/bind_test.cpp
    libc/test/src/sys/socket/linux/connect_accept_test.cpp
    libc/test/src/sys/socket/linux/listen_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index fe59cc04cc929..6eab12ec8b637 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -140,6 +140,7 @@ add_header_library(
   DEPENDS
     libc.src.__support.common
     libc.src.__support.CPP.string
+    libc.src.__support.CPP.string_view
 )
 
 add_header_library(

diff  --git a/libc/src/__support/c_string.h b/libc/src/__support/c_string.h
index 11f41320681af..1e7d5558f9001 100644
--- a/libc/src/__support/c_string.h
+++ b/libc/src/__support/c_string.h
@@ -10,6 +10,7 @@
 #define LLVM_LIBC_SRC___SUPPORT_C_STRING_H
 
 #include "src/__support/CPP/string.h"
+#include "src/__support/CPP/string_view.h"
 #include "src/__support/macros/attributes.h" // for LIBC_INLINE
 #include "src/__support/macros/config.h"
 
@@ -30,6 +31,7 @@ class CString {
   LIBC_INLINE CString(cpp::string in_str) : str(in_str) {}
 
   LIBC_INLINE operator const char *() const { return str.c_str(); }
+  LIBC_INLINE operator cpp::string_view() const { return str; }
 };
 
 } // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index 378529ca3b71f..636c5f316eb99 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -1,3 +1,18 @@
+add_header_library(
+  socket_test_support
+  HDRS
+    socket_test_support.h
+  DEPENDS
+    libc.hdr.sys_socket_macros
+    libc.hdr.types.size_t
+    libc.hdr.types.socklen_t
+    libc.hdr.types.struct_sockaddr_un
+    libc.src.__support.common
+    libc.src.__support.CPP.string_view
+    libc.src.string.strncpy
+    libc.src.string.strnlen
+)
+
 add_custom_target(libc_sys_socket_unittests)
 
 add_libc_unittest(
@@ -22,6 +37,7 @@ add_libc_unittest(
   SRCS
     bind_test.cpp
   DEPENDS
+    .socket_test_support
     libc.include.sys_socket
     libc.hdr.sys_socket_macros
     libc.hdr.types.struct_sockaddr_un
@@ -41,6 +57,7 @@ add_libc_unittest(
   SRCS
     connect_accept_test.cpp
   DEPENDS
+    .socket_test_support
     libc.include.sys_socket
     libc.hdr.fcntl_macros
     libc.hdr.sys_socket_macros
@@ -54,8 +71,6 @@ add_libc_unittest(
     libc.src.sys.socket.connect
     libc.src.sys.socket.listen
     libc.src.sys.socket.socket
-    libc.src.string.strlen
-    libc.src.string.strncpy
     libc.src.stdio.remove
     libc.src.unistd.close
     libc.test.UnitTest.ErrnoCheckingTest
@@ -69,6 +84,7 @@ add_libc_unittest(
   SRCS
     listen_test.cpp
   DEPENDS
+    .socket_test_support
     libc.include.sys_socket
     libc.hdr.sys_socket_macros
     libc.hdr.types.struct_sockaddr_un

diff  --git a/libc/test/src/sys/socket/linux/bind_test.cpp b/libc/test/src/sys/socket/linux/bind_test.cpp
index 03b8c18cfee83..231982a7c787a 100644
--- a/libc/test/src/sys/socket/linux/bind_test.cpp
+++ b/libc/test/src/sys/socket/linux/bind_test.cpp
@@ -17,6 +17,7 @@
 #include "test/UnitTest/ErrnoCheckingTest.h"
 #include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/Test.h"
+#include "test/src/sys/socket/linux/socket_test_support.h"
 
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
 using LlvmLibcBindTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
@@ -31,19 +32,7 @@ TEST_F(LlvmLibcBindTest, BindLocalSocket) {
   ASSERT_ERRNO_SUCCESS();
 
   struct sockaddr_un my_addr;
-
-  my_addr.sun_family = AF_UNIX;
-  unsigned int i = 0;
-  for (;
-       SOCK_PATH[i] != '\0' && (i < sizeof(sockaddr_un) - sizeof(sa_family_t));
-       ++i)
-    my_addr.sun_path[i] = SOCK_PATH[i];
-  my_addr.sun_path[i] = '\0';
-
-  // It's important that the path fits in the struct, if it doesn't then we
-  // can't try to bind to the file.
-  ASSERT_LT(
-      i, static_cast<unsigned int>(sizeof(sockaddr_un) - sizeof(sa_family_t)));
+  ASSERT_TRUE(LIBC_NAMESPACE::testing::make_sockaddr_un(SOCK_PATH, my_addr));
 
   ASSERT_THAT(
       LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),

diff  --git a/libc/test/src/sys/socket/linux/connect_accept_test.cpp b/libc/test/src/sys/socket/linux/connect_accept_test.cpp
index 1e9791041089c..fe3ff05b351df 100644
--- a/libc/test/src/sys/socket/linux/connect_accept_test.cpp
+++ b/libc/test/src/sys/socket/linux/connect_accept_test.cpp
@@ -11,48 +11,34 @@
 #include "hdr/types/size_t.h"
 #include "hdr/types/struct_sockaddr_un.h"
 #include "src/fcntl/fcntl.h"
+#include "src/stdio/remove.h"
 #include "src/sys/socket/accept.h"
 #include "src/sys/socket/accept4.h"
 #include "src/sys/socket/bind.h"
 #include "src/sys/socket/connect.h"
 #include "src/sys/socket/listen.h"
 #include "src/sys/socket/socket.h"
-
-#include "src/stdio/remove.h"
-#include "src/string/strlen.h"
-#include "src/string/strncpy.h"
 #include "src/unistd/close.h"
 
 #include "test/UnitTest/ErrnoCheckingTest.h"
 #include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
+#include "test/src/sys/socket/linux/socket_test_support.h"
 
+using LIBC_NAMESPACE::testing::make_sockaddr_un;
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
 using LlvmLibcConnectAcceptTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
 
-constexpr size_t MAX_SOCKET_PATH =
-    sizeof(struct sockaddr_un) - sizeof(sa_family_t);
-
-struct sockaddr_un make_sockaddr(const char *path) {
-  struct sockaddr_un result;
-  result.sun_family = AF_UNIX;
-  LIBC_NAMESPACE::strncpy(result.sun_path, path, MAX_SOCKET_PATH);
-  return result;
-}
-
 TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
   const char *CONNECT_FILE = "connect_file.test";
-  auto CONNECT_PATH = libc_make_test_file_path(CONNECT_FILE);
-  // It's important that the path fits in the struct, if it doesn't then we
-  // can't try to bind to the file.
-  ASSERT_LT(LIBC_NAMESPACE::strlen(CONNECT_PATH), MAX_SOCKET_PATH);
-  const struct sockaddr_un CONNECT_ADDR = make_sockaddr(CONNECT_PATH);
+  const auto CONNECT_PATH = libc_make_test_file_path(CONNECT_FILE);
+  struct sockaddr_un connect_addr;
+  ASSERT_TRUE(make_sockaddr_un(CONNECT_PATH, connect_addr));
 
   const char *ACCEPT_FILE = "accept_file.test";
-  auto ACCEPT_PATH = libc_make_test_file_path(ACCEPT_FILE);
-  ASSERT_LT(LIBC_NAMESPACE::strlen(ACCEPT_PATH), MAX_SOCKET_PATH);
-  const struct sockaddr_un ACCEPT_ADDR = make_sockaddr(ACCEPT_PATH);
+  const auto ACCEPT_PATH = libc_make_test_file_path(ACCEPT_FILE);
+  struct sockaddr_un accept_addr;
+  ASSERT_TRUE(make_sockaddr_un(ACCEPT_PATH, accept_addr));
 
   int accepting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
   ASSERT_GE(accepting_socket, 0);
@@ -60,7 +46,7 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
 
   ASSERT_THAT(LIBC_NAMESPACE::bind(
                   accepting_socket,
-                  reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+                  reinterpret_cast<const struct sockaddr *>(&accept_addr),
                   sizeof(struct sockaddr_un)),
               Succeeds(0));
 
@@ -73,7 +59,7 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
               Fails(EINVAL));
   ASSERT_THAT(LIBC_NAMESPACE::connect(
                   connecting_socket,
-                  reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+                  reinterpret_cast<const struct sockaddr *>(&accept_addr),
                   sizeof(struct sockaddr_un)),
               Fails(ECONNREFUSED));
 
@@ -81,7 +67,7 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
 
   ASSERT_THAT(LIBC_NAMESPACE::connect(
                   connecting_socket,
-                  reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+                  reinterpret_cast<const struct sockaddr *>(&accept_addr),
                   sizeof(struct sockaddr_un)),
               Succeeds(0));
 
@@ -99,13 +85,13 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
 
   ASSERT_THAT(LIBC_NAMESPACE::bind(
                   connecting_socket,
-                  reinterpret_cast<const struct sockaddr *>(&CONNECT_ADDR),
+                  reinterpret_cast<const struct sockaddr *>(&connect_addr),
                   sizeof(struct sockaddr_un)),
               Succeeds(0));
 
   ASSERT_THAT(LIBC_NAMESPACE::connect(
                   connecting_socket,
-                  reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+                  reinterpret_cast<const struct sockaddr *>(&accept_addr),
                   sizeof(struct sockaddr_un)),
               Succeeds(0));
 
@@ -117,9 +103,9 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
   ASSERT_GE(accepted_socket, 0);
   ASSERT_ERRNO_SUCCESS();
   ASSERT_THAT(LIBC_NAMESPACE::close(accepted_socket), Succeeds(0));
-  ASSERT_EQ(accepted_addr.sun_family, static_cast<sa_family_t>(AF_UNIX));
-  for (size_t i = 0; i < accepted_addr_len - sizeof(sa_family_t); ++i)
-    ASSERT_EQ(accepted_addr.sun_path[i], CONNECT_ADDR.sun_path[i]);
+  ASSERT_THAT((LIBC_NAMESPACE::testing::SocketAddress{accepted_addr,
+                                                      accepted_addr_len}),
+              LIBC_NAMESPACE::testing::MatchesAddress(CONNECT_PATH));
 
   ASSERT_THAT(LIBC_NAMESPACE::close(accepting_socket), Succeeds(0));
   ASSERT_THAT(LIBC_NAMESPACE::close(connecting_socket), Succeeds(0));
@@ -130,8 +116,8 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
 TEST_F(LlvmLibcConnectAcceptTest, Accept4Flags) {
   const char *ACCEPT_FILE = "accept4_file.test";
   auto ACCEPT_PATH = libc_make_test_file_path(ACCEPT_FILE);
-  ASSERT_LT(LIBC_NAMESPACE::strlen(ACCEPT_PATH), MAX_SOCKET_PATH);
-  const struct sockaddr_un ACCEPT_ADDR = make_sockaddr(ACCEPT_PATH);
+  struct sockaddr_un accept_addr;
+  ASSERT_TRUE(make_sockaddr_un(ACCEPT_PATH, accept_addr));
 
   int accepting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
   ASSERT_GE(accepting_socket, 0);
@@ -139,7 +125,7 @@ TEST_F(LlvmLibcConnectAcceptTest, Accept4Flags) {
 
   ASSERT_THAT(LIBC_NAMESPACE::bind(
                   accepting_socket,
-                  reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+                  reinterpret_cast<const struct sockaddr *>(&accept_addr),
                   sizeof(struct sockaddr_un)),
               Succeeds(0));
 
@@ -155,7 +141,7 @@ TEST_F(LlvmLibcConnectAcceptTest, Accept4Flags) {
 
   ASSERT_THAT(LIBC_NAMESPACE::connect(
                   connecting_socket,
-                  reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+                  reinterpret_cast<const struct sockaddr *>(&accept_addr),
                   sizeof(struct sockaddr_un)),
               Succeeds(0));
 

diff  --git a/libc/test/src/sys/socket/linux/listen_test.cpp b/libc/test/src/sys/socket/linux/listen_test.cpp
index 71553a8a62862..cf78c57de7896 100644
--- a/libc/test/src/sys/socket/linux/listen_test.cpp
+++ b/libc/test/src/sys/socket/linux/listen_test.cpp
@@ -17,7 +17,7 @@
 
 #include "test/UnitTest/ErrnoCheckingTest.h"
 #include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
+#include "test/src/sys/socket/linux/socket_test_support.h"
 
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
@@ -33,15 +33,7 @@ TEST_F(LlvmLibcListenTest, ListenLocalSocket) {
   ASSERT_ERRNO_SUCCESS();
 
   struct sockaddr_un my_addr;
-
-  my_addr.sun_family = AF_UNIX;
-  unsigned int i = 0;
-  for (;
-       SOCK_PATH[i] != '\0' && (i < sizeof(sockaddr_un) - sizeof(sa_family_t));
-       ++i)
-    my_addr.sun_path[i] = SOCK_PATH[i];
-
-  my_addr.sun_path[i] = '\0';
+  ASSERT_TRUE(LIBC_NAMESPACE::testing::make_sockaddr_un(SOCK_PATH, my_addr));
 
   ASSERT_THAT(
       LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),

diff  --git a/libc/test/src/sys/socket/linux/socket_test_support.h b/libc/test/src/sys/socket/linux/socket_test_support.h
new file mode 100644
index 0000000000000..ea9130a1644ce
--- /dev/null
+++ b/libc/test/src/sys/socket/linux/socket_test_support.h
@@ -0,0 +1,112 @@
+//===-- Helpers for socket tests --------------------------------*- C++ -*-===//
+//
+// 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_TEST_SRC_SYS_SOCKET_LINUX_SOCKET_TEST_SUPPORT_H
+#define LLVM_LIBC_TEST_SRC_SYS_SOCKET_LINUX_SOCKET_TEST_SUPPORT_H
+
+#include "hdr/sys_socket_macros.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/socklen_t.h"
+#include "hdr/types/struct_sockaddr_un.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/common.h"
+#include "src/string/strncpy.h"
+#include "src/string/strnlen.h"
+#include "test/UnitTest/LibcTest.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace testing {
+
+[[nodiscard]] LIBC_INLINE bool make_sockaddr_un(cpp::string_view path,
+                                                struct sockaddr_un &sun) {
+  sun.sun_family = AF_UNIX;
+  // The kernel accepts addresses which fill the entire sun_path buffer (without
+  // the terminating '\0' character), but we don't do that as it makes matching
+  // the returned values more 
diff icult.
+  if (path.size() + 1 > sizeof(sun.sun_path))
+    return false;
+  strncpy(sun.sun_path, path.data(), sizeof(sun.sun_path));
+  return true;
+}
+
+struct SocketAddress {
+  struct sockaddr_un addr;
+  socklen_t addrlen;
+};
+
+class SocketAddressMatcher : public Matcher<SocketAddress> {
+  cpp::string_view expected_path;
+  struct sockaddr_un actual_addr;
+  socklen_t actual_addrlen;
+
+  static constexpr size_t SUN_PATH_OFFSET =
+      offsetof(struct sockaddr_un, sun_path);
+
+public:
+  explicit SocketAddressMatcher(cpp::string_view path) : expected_path(path) {}
+
+  bool match(const SocketAddress &actual) {
+    actual_addr = actual.addr;
+    actual_addrlen = actual.addrlen;
+    if (actual_addr.sun_family != AF_UNIX)
+      return false;
+    if (actual_addrlen > sizeof(actual_addr))
+      return false;
+    size_t expected_path_len = expected_path.size();
+    if (expected_path_len + 1 + SUN_PATH_OFFSET > actual_addrlen)
+      return false;
+    if (actual_addrlen < SUN_PATH_OFFSET)
+      return false;
+    cpp::string_view actual_path(
+        actual_addr.sun_path,
+        strnlen(actual_addr.sun_path, actual_addrlen - SUN_PATH_OFFSET));
+    return actual_path == expected_path;
+  }
+
+  void explainError() override {
+    if (actual_addr.sun_family != AF_UNIX) {
+      tlog << "Expected address family to be AF_UNIX but got "
+           << actual_addr.sun_family << "\n";
+      return;
+    }
+    if (actual_addrlen > sizeof(actual_addr)) {
+      tlog << "Expected address length to be less than or equal to "
+           << sizeof(actual_addr) << " but got " << actual_addrlen << "\n";
+      return;
+    }
+    size_t expected_path_len = expected_path.size();
+    if (expected_path_len + 1 + SUN_PATH_OFFSET > actual_addrlen) {
+      tlog << "Expected address length to be less than or equal to "
+           << expected_path_len + 1 + SUN_PATH_OFFSET << " but got "
+           << actual_addrlen << "\n";
+      return;
+    }
+    if (actual_addrlen < SUN_PATH_OFFSET) {
+      tlog << "Expected address length to be greater than or equal to "
+           << SUN_PATH_OFFSET << " but got " << actual_addrlen << "\n";
+      return;
+    }
+    cpp::string_view actual_path(
+        actual_addr.sun_path,
+        strnlen(actual_addr.sun_path, actual_addrlen - SUN_PATH_OFFSET));
+    if (actual_path != expected_path) {
+      tlog << "Expected address path to be " << expected_path << " but got "
+           << actual_path << "\n";
+      return;
+    }
+  }
+};
+
+LIBC_INLINE SocketAddressMatcher MatchesAddress(cpp::string_view path) {
+  return SocketAddressMatcher(path);
+}
+
+} // namespace testing
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_TEST_SRC_SYS_SOCKET_LINUX_SOCKET_TEST_SUPPORT_H


        


More information about the libc-commits mailing list