Skip to content

Commit f3294c2

Browse files
authored
[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.
1 parent a62b65e commit f3294c2

7 files changed

Lines changed: 158 additions & 60 deletions

File tree

libc/src/__support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ add_header_library(
140140
DEPENDS
141141
libc.src.__support.common
142142
libc.src.__support.CPP.string
143+
libc.src.__support.CPP.string_view
143144
)
144145

145146
add_header_library(

libc/src/__support/c_string.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLVM_LIBC_SRC___SUPPORT_C_STRING_H
1111

1212
#include "src/__support/CPP/string.h"
13+
#include "src/__support/CPP/string_view.h"
1314
#include "src/__support/macros/attributes.h" // for LIBC_INLINE
1415
#include "src/__support/macros/config.h"
1516

@@ -30,6 +31,7 @@ class CString {
3031
LIBC_INLINE CString(cpp::string in_str) : str(in_str) {}
3132

3233
LIBC_INLINE operator const char *() const { return str.c_str(); }
34+
LIBC_INLINE operator cpp::string_view() const { return str; }
3335
};
3436

3537
} // namespace LIBC_NAMESPACE_DECL

libc/test/src/sys/socket/linux/CMakeLists.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
add_header_library(
2+
socket_test_support
3+
HDRS
4+
socket_test_support.h
5+
DEPENDS
6+
libc.hdr.sys_socket_macros
7+
libc.hdr.types.size_t
8+
libc.hdr.types.socklen_t
9+
libc.hdr.types.struct_sockaddr_un
10+
libc.src.__support.common
11+
libc.src.__support.CPP.string_view
12+
libc.src.string.strncpy
13+
libc.src.string.strnlen
14+
)
15+
116
add_custom_target(libc_sys_socket_unittests)
217

318
add_libc_unittest(
@@ -22,6 +37,7 @@ add_libc_unittest(
2237
SRCS
2338
bind_test.cpp
2439
DEPENDS
40+
.socket_test_support
2541
libc.include.sys_socket
2642
libc.hdr.sys_socket_macros
2743
libc.hdr.types.struct_sockaddr_un
@@ -41,6 +57,7 @@ add_libc_unittest(
4157
SRCS
4258
connect_accept_test.cpp
4359
DEPENDS
60+
.socket_test_support
4461
libc.include.sys_socket
4562
libc.hdr.fcntl_macros
4663
libc.hdr.sys_socket_macros
@@ -54,8 +71,6 @@ add_libc_unittest(
5471
libc.src.sys.socket.connect
5572
libc.src.sys.socket.listen
5673
libc.src.sys.socket.socket
57-
libc.src.string.strlen
58-
libc.src.string.strncpy
5974
libc.src.stdio.remove
6075
libc.src.unistd.close
6176
libc.test.UnitTest.ErrnoCheckingTest
@@ -69,6 +84,7 @@ add_libc_unittest(
6984
SRCS
7085
listen_test.cpp
7186
DEPENDS
87+
.socket_test_support
7288
libc.include.sys_socket
7389
libc.hdr.sys_socket_macros
7490
libc.hdr.types.struct_sockaddr_un

libc/test/src/sys/socket/linux/bind_test.cpp

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "test/UnitTest/ErrnoCheckingTest.h"
1818
#include "test/UnitTest/ErrnoSetterMatcher.h"
1919
#include "test/UnitTest/Test.h"
20+
#include "test/src/sys/socket/linux/socket_test_support.h"
2021

2122
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
2223
using LlvmLibcBindTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
@@ -31,19 +32,7 @@ TEST_F(LlvmLibcBindTest, BindLocalSocket) {
3132
ASSERT_ERRNO_SUCCESS();
3233

3334
struct sockaddr_un my_addr;
34-
35-
my_addr.sun_family = AF_UNIX;
36-
unsigned int i = 0;
37-
for (;
38-
SOCK_PATH[i] != '\0' && (i < sizeof(sockaddr_un) - sizeof(sa_family_t));
39-
++i)
40-
my_addr.sun_path[i] = SOCK_PATH[i];
41-
my_addr.sun_path[i] = '\0';
42-
43-
// It's important that the path fits in the struct, if it doesn't then we
44-
// can't try to bind to the file.
45-
ASSERT_LT(
46-
i, static_cast<unsigned int>(sizeof(sockaddr_un) - sizeof(sa_family_t)));
35+
ASSERT_TRUE(LIBC_NAMESPACE::testing::make_sockaddr_un(SOCK_PATH, my_addr));
4736

4837
ASSERT_THAT(
4938
LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),

libc/test/src/sys/socket/linux/connect_accept_test.cpp

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,56 +11,42 @@
1111
#include "hdr/types/size_t.h"
1212
#include "hdr/types/struct_sockaddr_un.h"
1313
#include "src/fcntl/fcntl.h"
14+
#include "src/stdio/remove.h"
1415
#include "src/sys/socket/accept.h"
1516
#include "src/sys/socket/accept4.h"
1617
#include "src/sys/socket/bind.h"
1718
#include "src/sys/socket/connect.h"
1819
#include "src/sys/socket/listen.h"
1920
#include "src/sys/socket/socket.h"
20-
21-
#include "src/stdio/remove.h"
22-
#include "src/string/strlen.h"
23-
#include "src/string/strncpy.h"
2421
#include "src/unistd/close.h"
2522

2623
#include "test/UnitTest/ErrnoCheckingTest.h"
2724
#include "test/UnitTest/ErrnoSetterMatcher.h"
28-
#include "test/UnitTest/Test.h"
25+
#include "test/src/sys/socket/linux/socket_test_support.h"
2926

27+
using LIBC_NAMESPACE::testing::make_sockaddr_un;
3028
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
3129
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
3230
using LlvmLibcConnectAcceptTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
3331

34-
constexpr size_t MAX_SOCKET_PATH =
35-
sizeof(struct sockaddr_un) - sizeof(sa_family_t);
36-
37-
struct sockaddr_un make_sockaddr(const char *path) {
38-
struct sockaddr_un result;
39-
result.sun_family = AF_UNIX;
40-
LIBC_NAMESPACE::strncpy(result.sun_path, path, MAX_SOCKET_PATH);
41-
return result;
42-
}
43-
4432
TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
4533
const char *CONNECT_FILE = "connect_file.test";
46-
auto CONNECT_PATH = libc_make_test_file_path(CONNECT_FILE);
47-
// It's important that the path fits in the struct, if it doesn't then we
48-
// can't try to bind to the file.
49-
ASSERT_LT(LIBC_NAMESPACE::strlen(CONNECT_PATH), MAX_SOCKET_PATH);
50-
const struct sockaddr_un CONNECT_ADDR = make_sockaddr(CONNECT_PATH);
34+
const auto CONNECT_PATH = libc_make_test_file_path(CONNECT_FILE);
35+
struct sockaddr_un connect_addr;
36+
ASSERT_TRUE(make_sockaddr_un(CONNECT_PATH, connect_addr));
5137

5238
const char *ACCEPT_FILE = "accept_file.test";
53-
auto ACCEPT_PATH = libc_make_test_file_path(ACCEPT_FILE);
54-
ASSERT_LT(LIBC_NAMESPACE::strlen(ACCEPT_PATH), MAX_SOCKET_PATH);
55-
const struct sockaddr_un ACCEPT_ADDR = make_sockaddr(ACCEPT_PATH);
39+
const auto ACCEPT_PATH = libc_make_test_file_path(ACCEPT_FILE);
40+
struct sockaddr_un accept_addr;
41+
ASSERT_TRUE(make_sockaddr_un(ACCEPT_PATH, accept_addr));
5642

5743
int accepting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
5844
ASSERT_GE(accepting_socket, 0);
5945
ASSERT_ERRNO_SUCCESS();
6046

6147
ASSERT_THAT(LIBC_NAMESPACE::bind(
6248
accepting_socket,
63-
reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
49+
reinterpret_cast<const struct sockaddr *>(&accept_addr),
6450
sizeof(struct sockaddr_un)),
6551
Succeeds(0));
6652

@@ -73,15 +59,15 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
7359
Fails(EINVAL));
7460
ASSERT_THAT(LIBC_NAMESPACE::connect(
7561
connecting_socket,
76-
reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
62+
reinterpret_cast<const struct sockaddr *>(&accept_addr),
7763
sizeof(struct sockaddr_un)),
7864
Fails(ECONNREFUSED));
7965

8066
ASSERT_THAT(LIBC_NAMESPACE::listen(accepting_socket, 1), Succeeds(0));
8167

8268
ASSERT_THAT(LIBC_NAMESPACE::connect(
8369
connecting_socket,
84-
reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
70+
reinterpret_cast<const struct sockaddr *>(&accept_addr),
8571
sizeof(struct sockaddr_un)),
8672
Succeeds(0));
8773

@@ -99,13 +85,13 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
9985

10086
ASSERT_THAT(LIBC_NAMESPACE::bind(
10187
connecting_socket,
102-
reinterpret_cast<const struct sockaddr *>(&CONNECT_ADDR),
88+
reinterpret_cast<const struct sockaddr *>(&connect_addr),
10389
sizeof(struct sockaddr_un)),
10490
Succeeds(0));
10591

10692
ASSERT_THAT(LIBC_NAMESPACE::connect(
10793
connecting_socket,
108-
reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
94+
reinterpret_cast<const struct sockaddr *>(&accept_addr),
10995
sizeof(struct sockaddr_un)),
11096
Succeeds(0));
11197

@@ -117,9 +103,9 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
117103
ASSERT_GE(accepted_socket, 0);
118104
ASSERT_ERRNO_SUCCESS();
119105
ASSERT_THAT(LIBC_NAMESPACE::close(accepted_socket), Succeeds(0));
120-
ASSERT_EQ(accepted_addr.sun_family, static_cast<sa_family_t>(AF_UNIX));
121-
for (size_t i = 0; i < accepted_addr_len - sizeof(sa_family_t); ++i)
122-
ASSERT_EQ(accepted_addr.sun_path[i], CONNECT_ADDR.sun_path[i]);
106+
ASSERT_THAT((LIBC_NAMESPACE::testing::SocketAddress{accepted_addr,
107+
accepted_addr_len}),
108+
LIBC_NAMESPACE::testing::MatchesAddress(CONNECT_PATH));
123109

124110
ASSERT_THAT(LIBC_NAMESPACE::close(accepting_socket), Succeeds(0));
125111
ASSERT_THAT(LIBC_NAMESPACE::close(connecting_socket), Succeeds(0));
@@ -130,16 +116,16 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
130116
TEST_F(LlvmLibcConnectAcceptTest, Accept4Flags) {
131117
const char *ACCEPT_FILE = "accept4_file.test";
132118
auto ACCEPT_PATH = libc_make_test_file_path(ACCEPT_FILE);
133-
ASSERT_LT(LIBC_NAMESPACE::strlen(ACCEPT_PATH), MAX_SOCKET_PATH);
134-
const struct sockaddr_un ACCEPT_ADDR = make_sockaddr(ACCEPT_PATH);
119+
struct sockaddr_un accept_addr;
120+
ASSERT_TRUE(make_sockaddr_un(ACCEPT_PATH, accept_addr));
135121

136122
int accepting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
137123
ASSERT_GE(accepting_socket, 0);
138124
ASSERT_ERRNO_SUCCESS();
139125

140126
ASSERT_THAT(LIBC_NAMESPACE::bind(
141127
accepting_socket,
142-
reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
128+
reinterpret_cast<const struct sockaddr *>(&accept_addr),
143129
sizeof(struct sockaddr_un)),
144130
Succeeds(0));
145131

@@ -155,7 +141,7 @@ TEST_F(LlvmLibcConnectAcceptTest, Accept4Flags) {
155141

156142
ASSERT_THAT(LIBC_NAMESPACE::connect(
157143
connecting_socket,
158-
reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
144+
reinterpret_cast<const struct sockaddr *>(&accept_addr),
159145
sizeof(struct sockaddr_un)),
160146
Succeeds(0));
161147

libc/test/src/sys/socket/linux/listen_test.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include "test/UnitTest/ErrnoCheckingTest.h"
1919
#include "test/UnitTest/ErrnoSetterMatcher.h"
20-
#include "test/UnitTest/Test.h"
20+
#include "test/src/sys/socket/linux/socket_test_support.h"
2121

2222
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
2323
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
@@ -33,15 +33,7 @@ TEST_F(LlvmLibcListenTest, ListenLocalSocket) {
3333
ASSERT_ERRNO_SUCCESS();
3434

3535
struct sockaddr_un my_addr;
36-
37-
my_addr.sun_family = AF_UNIX;
38-
unsigned int i = 0;
39-
for (;
40-
SOCK_PATH[i] != '\0' && (i < sizeof(sockaddr_un) - sizeof(sa_family_t));
41-
++i)
42-
my_addr.sun_path[i] = SOCK_PATH[i];
43-
44-
my_addr.sun_path[i] = '\0';
36+
ASSERT_TRUE(LIBC_NAMESPACE::testing::make_sockaddr_un(SOCK_PATH, my_addr));
4537

4638
ASSERT_THAT(
4739
LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//===-- Helpers for socket tests --------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_TEST_SRC_SYS_SOCKET_LINUX_SOCKET_TEST_SUPPORT_H
10+
#define LLVM_LIBC_TEST_SRC_SYS_SOCKET_LINUX_SOCKET_TEST_SUPPORT_H
11+
12+
#include "hdr/sys_socket_macros.h"
13+
#include "hdr/types/size_t.h"
14+
#include "hdr/types/socklen_t.h"
15+
#include "hdr/types/struct_sockaddr_un.h"
16+
#include "src/__support/CPP/string_view.h"
17+
#include "src/__support/common.h"
18+
#include "src/string/strncpy.h"
19+
#include "src/string/strnlen.h"
20+
#include "test/UnitTest/LibcTest.h"
21+
22+
namespace LIBC_NAMESPACE_DECL {
23+
namespace testing {
24+
25+
[[nodiscard]] LIBC_INLINE bool make_sockaddr_un(cpp::string_view path,
26+
struct sockaddr_un &sun) {
27+
sun.sun_family = AF_UNIX;
28+
// The kernel accepts addresses which fill the entire sun_path buffer (without
29+
// the terminating '\0' character), but we don't do that as it makes matching
30+
// the returned values more difficult.
31+
if (path.size() + 1 > sizeof(sun.sun_path))
32+
return false;
33+
strncpy(sun.sun_path, path.data(), sizeof(sun.sun_path));
34+
return true;
35+
}
36+
37+
struct SocketAddress {
38+
struct sockaddr_un addr;
39+
socklen_t addrlen;
40+
};
41+
42+
class SocketAddressMatcher : public Matcher<SocketAddress> {
43+
cpp::string_view expected_path;
44+
struct sockaddr_un actual_addr;
45+
socklen_t actual_addrlen;
46+
47+
static constexpr size_t SUN_PATH_OFFSET =
48+
offsetof(struct sockaddr_un, sun_path);
49+
50+
public:
51+
explicit SocketAddressMatcher(cpp::string_view path) : expected_path(path) {}
52+
53+
bool match(const SocketAddress &actual) {
54+
actual_addr = actual.addr;
55+
actual_addrlen = actual.addrlen;
56+
if (actual_addr.sun_family != AF_UNIX)
57+
return false;
58+
if (actual_addrlen > sizeof(actual_addr))
59+
return false;
60+
size_t expected_path_len = expected_path.size();
61+
if (expected_path_len + 1 + SUN_PATH_OFFSET > actual_addrlen)
62+
return false;
63+
if (actual_addrlen < SUN_PATH_OFFSET)
64+
return false;
65+
cpp::string_view actual_path(
66+
actual_addr.sun_path,
67+
strnlen(actual_addr.sun_path, actual_addrlen - SUN_PATH_OFFSET));
68+
return actual_path == expected_path;
69+
}
70+
71+
void explainError() override {
72+
if (actual_addr.sun_family != AF_UNIX) {
73+
tlog << "Expected address family to be AF_UNIX but got "
74+
<< actual_addr.sun_family << "\n";
75+
return;
76+
}
77+
if (actual_addrlen > sizeof(actual_addr)) {
78+
tlog << "Expected address length to be less than or equal to "
79+
<< sizeof(actual_addr) << " but got " << actual_addrlen << "\n";
80+
return;
81+
}
82+
size_t expected_path_len = expected_path.size();
83+
if (expected_path_len + 1 + SUN_PATH_OFFSET > actual_addrlen) {
84+
tlog << "Expected address length to be less than or equal to "
85+
<< expected_path_len + 1 + SUN_PATH_OFFSET << " but got "
86+
<< actual_addrlen << "\n";
87+
return;
88+
}
89+
if (actual_addrlen < SUN_PATH_OFFSET) {
90+
tlog << "Expected address length to be greater than or equal to "
91+
<< SUN_PATH_OFFSET << " but got " << actual_addrlen << "\n";
92+
return;
93+
}
94+
cpp::string_view actual_path(
95+
actual_addr.sun_path,
96+
strnlen(actual_addr.sun_path, actual_addrlen - SUN_PATH_OFFSET));
97+
if (actual_path != expected_path) {
98+
tlog << "Expected address path to be " << expected_path << " but got "
99+
<< actual_path << "\n";
100+
return;
101+
}
102+
}
103+
};
104+
105+
LIBC_INLINE SocketAddressMatcher MatchesAddress(cpp::string_view path) {
106+
return SocketAddressMatcher(path);
107+
}
108+
109+
} // namespace testing
110+
} // namespace LIBC_NAMESPACE_DECL
111+
112+
#endif // LLVM_LIBC_TEST_SRC_SYS_SOCKET_LINUX_SOCKET_TEST_SUPPORT_H

0 commit comments

Comments
 (0)