[libc-commits] [libc] [libc] Add socket test support library (PR #193207)
via libc-commits
libc-commits at lists.llvm.org
Tue Apr 21 05:57:47 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Pavel Labath (labath)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/193207.diff
5 Files Affected:
- (modified) libc/test/src/sys/socket/linux/CMakeLists.txt (+17-2)
- (modified) libc/test/src/sys/socket/linux/bind_test.cpp (+2-13)
- (modified) libc/test/src/sys/socket/linux/connect_accept_test.cpp (+19-31)
- (modified) libc/test/src/sys/socket/linux/listen_test.cpp (+2-10)
- (added) libc/test/src/sys/socket/linux/socket_test_support.h (+92)
``````````diff
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index dec0a322d3bd9..2c5c8e1f7f54b 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -1,3 +1,17 @@
+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.string.strlen
+ libc.src.string.strncmp
+ libc.src.string.strncpy
+)
+
add_custom_target(libc_sys_socket_unittests)
add_libc_unittest(
@@ -22,6 +36,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 +56,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 +70,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 +83,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..497fe68736676 100644
--- a/libc/test/src/sys/socket/linux/connect_accept_test.cpp
+++ b/libc/test/src/sys/socket/linux/connect_accept_test.cpp
@@ -19,40 +19,28 @@
#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);
+ 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);
+ 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 +48,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 +61,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 +69,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 +87,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 +105,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 +118,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 +127,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 +143,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..3d691537da954
--- /dev/null
+++ b/libc/test/src/sys/socket/linux/socket_test_support.h
@@ -0,0 +1,92 @@
+//===-- 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/common.h"
+#include "src/string/strlen.h"
+#include "src/string/strncmp.h"
+#include "src/string/strncpy.h"
+#include "test/UnitTest/LibcTest.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace testing {
+
+LIBC_INLINE bool make_sockaddr_un(const char *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 difficult.
+ if (strlen(path) + 1 > sizeof(sun.sun_path))
+ return false;
+ strncpy(sun.sun_path, path, sizeof(sun.sun_path));
+ return true;
+}
+
+struct SocketAddress {
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+};
+
+class SocketAddressMatcher : public Matcher<SocketAddress> {
+ const char *expected_path;
+ struct sockaddr_un actual_addr;
+ socklen_t actual_addrlen;
+
+public:
+ explicit SocketAddressMatcher(const char *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 = strlen(expected_path);
+ if (expected_path_len + 1 + sizeof(actual_addr.sun_family) > actual_addrlen)
+ return false;
+ return strncmp(actual_addr.sun_path, expected_path, expected_path_len) == 0;
+ }
+
+ 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";
+ }
+ 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";
+ }
+ size_t expected_path_len = strlen(expected_path);
+ if (expected_path_len + 1 + sizeof(actual_addr.sun_family) >
+ actual_addrlen) {
+ tlog << "Expected address length to be less than or equal to "
+ << expected_path_len + 1 + sizeof(actual_addr.sun_family)
+ << " but got " << actual_addrlen << "\n";
+ }
+ if (strncmp(actual_addr.sun_path, expected_path, expected_path_len) != 0) {
+ tlog << "Expected address path to be " << expected_path << " but got "
+ << actual_addr.sun_path << "\n";
+ }
+ }
+};
+
+LIBC_INLINE SocketAddressMatcher MatchesAddress(const char *path) {
+ return SocketAddressMatcher(path);
+}
+
+} // namespace testing
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_TEST_SRC_SYS_SOCKET_LINUX_SOCKET_TEST_SUPPORT_H
``````````
</details>
https://github.com/llvm/llvm-project/pull/193207
More information about the libc-commits
mailing list