[libc-commits] [libc] [libc] Add a simple scope_exit wrapper and use it in socket tests (PR #192615)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Tue May 5 08:30:30 PDT 2026
https://github.com/labath updated https://github.com/llvm/llvm-project/pull/192615
>From 947b29dd413edc462cd4e551869725891ef299ae Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Fri, 17 Apr 2026 08:01:45 +0000
Subject: [PATCH 1/2] [libc] Add a simple scope_exit wrapper and use it in
socket tests
This is slightly different from the other CPP reimplementations in that
the real scope_exit is only an experimental C++ class. If that's an
issue, I'm happy to put the class somewhere else.
It could probably be used in more places, but right now I'm adding it to
socket tests, as that's what I'm familiar with. It (mostly -- it doesn't
help with crashes) solves the issue where a failing test does not clean
up the unix domain socket, which then fails the test on the subsequent
run.
---
libc/src/__support/CPP/CMakeLists.txt | 8 ++
libc/src/__support/CPP/scope.h | 52 ++++++++++++
libc/test/src/__support/CPP/CMakeLists.txt | 10 +++
libc/test/src/__support/CPP/scope_test.cpp | 49 +++++++++++
libc/test/src/sys/socket/linux/CMakeLists.txt | 7 ++
libc/test/src/sys/socket/linux/bind_test.cpp | 4 +-
.../sys/socket/linux/connect_accept_test.cpp | 81 +++++++++++--------
.../test/src/sys/socket/linux/listen_test.cpp | 9 ++-
.../src/sys/socket/linux/send_recv_test.cpp | 9 ++-
.../sys/socket/linux/sendmsg_recvmsg_test.cpp | 9 ++-
.../sys/socket/linux/sendto_recvfrom_test.cpp | 9 ++-
.../src/sys/socket/linux/socketopt_test.cpp | 9 ++-
12 files changed, 202 insertions(+), 54 deletions(-)
create mode 100644 libc/src/__support/CPP/scope.h
create mode 100644 libc/test/src/__support/CPP/scope_test.cpp
diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt
index bdfbc6151c773..03e21ac6c80ca 100644
--- a/libc/src/__support/CPP/CMakeLists.txt
+++ b/libc/src/__support/CPP/CMakeLists.txt
@@ -214,6 +214,14 @@ add_object_library(
libc.src.__support.macros.properties.os
)
+add_header_library(
+ scope
+ HDRS
+ scope.h
+ DEPENDS
+ .utility
+)
+
add_header_library(
tuple
HDRS
diff --git a/libc/src/__support/CPP/scope.h b/libc/src/__support/CPP/scope.h
new file mode 100644
index 0000000000000..38f9dae20035e
--- /dev/null
+++ b/libc/src/__support/CPP/scope.h
@@ -0,0 +1,52 @@
+//===-- Standalone implementation of experimental/scope_exit ----*- 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_SRC___SUPPORT_CPP_SCOPE_H
+#define LLVM_LIBC_SRC___SUPPORT_CPP_SCOPE_H
+
+#include "src/__support/CPP/utility/forward.h"
+#include "src/__support/CPP/utility/move.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace cpp {
+
+template <typename EF> class scope_exit {
+ EF exit_function;
+ bool execute_on_destruction;
+
+public:
+ template <typename Fn>
+ LIBC_INLINE explicit scope_exit(Fn &&fn)
+ : exit_function(cpp::forward<Fn>(fn)), execute_on_destruction(true) {}
+
+ LIBC_INLINE scope_exit(scope_exit &&other)
+ : exit_function(cpp::move(other.exit_function)),
+ execute_on_destruction(other.execute_on_destruction) {
+ other.release();
+ }
+
+ scope_exit(const scope_exit &) = delete;
+ scope_exit &operator=(const scope_exit &) = delete;
+ scope_exit &operator=(scope_exit &&) = delete;
+
+ LIBC_INLINE ~scope_exit() {
+ if (execute_on_destruction)
+ exit_function();
+ }
+
+ LIBC_INLINE void release() { execute_on_destruction = false; }
+};
+
+template <typename EF> scope_exit(EF) -> scope_exit<EF>;
+
+} // namespace cpp
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_CPP_SCOPE_H
diff --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt
index 430cd7b136c69..1d47455dcd31f 100644
--- a/libc/test/src/__support/CPP/CMakeLists.txt
+++ b/libc/test/src/__support/CPP/CMakeLists.txt
@@ -140,6 +140,16 @@ add_libc_test(
libc.src.__support.CPP.tuple
)
+add_libc_test(
+ scope_test
+ SUITE
+ libc-cpp-utils-tests
+ SRCS
+ scope_test.cpp
+ DEPENDS
+ libc.src.__support.CPP.scope
+)
+
add_libc_test(
span_test
SUITE
diff --git a/libc/test/src/__support/CPP/scope_test.cpp b/libc/test/src/__support/CPP/scope_test.cpp
new file mode 100644
index 0000000000000..c74bf218f91fc
--- /dev/null
+++ b/libc/test/src/__support/CPP/scope_test.cpp
@@ -0,0 +1,49 @@
+//===-- Unittests for scope_exit ------------------------------------------===//
+//
+// 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 "src/__support/CPP/scope.h"
+#include "src/__support/CPP/utility/move.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::cpp::scope_exit;
+
+TEST(LlvmLibcScopeExitTest, Basic) {
+ bool called = false;
+ {
+ scope_exit cleanup([&called] { called = true; });
+ ASSERT_FALSE(called);
+ }
+ ASSERT_TRUE(called);
+}
+
+TEST(LlvmLibcScopeExitTest, Release) {
+ bool called = false;
+ {
+ scope_exit cleanup([&called] { called = true; });
+ ASSERT_FALSE(called);
+ cleanup.release();
+ }
+ ASSERT_FALSE(called);
+}
+
+TEST(LlvmLibcScopeExitTest, Move) {
+ bool called = false;
+ {
+ scope_exit cleanup1([&called] { called = true; });
+ {
+ scope_exit cleanup2(LIBC_NAMESPACE::cpp::move(cleanup1));
+ ASSERT_FALSE(called);
+ }
+ // cleanup2 goes out of scope here, should call the function.
+ ASSERT_TRUE(called);
+ called = false; // reset
+ }
+ // cleanup1 goes out of scope here, but it was moved from, so it shouldn't
+ // call.
+ ASSERT_FALSE(called);
+}
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index c8a08b0557ce9..d3f2c480bdd28 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -30,6 +30,7 @@ add_libc_unittest(
libc.src.sys.socket.bind
libc.src.stdio.remove
libc.src.unistd.close
+ libc.src.__support.CPP.scope
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
@@ -55,6 +56,7 @@ add_libc_unittest(
libc.src.string.strncpy
libc.src.stdio.remove
libc.src.unistd.close
+ libc.src.__support.CPP.scope
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
@@ -75,6 +77,7 @@ add_libc_unittest(
libc.src.sys.socket.listen
libc.src.stdio.remove
libc.src.unistd.close
+ libc.src.__support.CPP.scope
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
@@ -95,6 +98,7 @@ add_libc_unittest(
libc.src.sys.socket.socket
libc.src.unistd.close
libc.src.unistd.pipe
+ libc.src.__support.CPP.scope
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
@@ -127,6 +131,7 @@ add_libc_unittest(
libc.src.sys.socket.send
libc.src.sys.socket.recv
libc.src.unistd.close
+ libc.src.__support.CPP.scope
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
@@ -144,6 +149,7 @@ add_libc_unittest(
libc.src.sys.socket.sendto
libc.src.sys.socket.recvfrom
libc.src.unistd.close
+ libc.src.__support.CPP.scope
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
@@ -161,6 +167,7 @@ add_libc_unittest(
libc.src.sys.socket.sendmsg
libc.src.sys.socket.recvmsg
libc.src.unistd.close
+ libc.src.__support.CPP.scope
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
diff --git a/libc/test/src/sys/socket/linux/bind_test.cpp b/libc/test/src/sys/socket/linux/bind_test.cpp
index 03b8c18cfee83..026d16c5ba1c9 100644
--- a/libc/test/src/sys/socket/linux/bind_test.cpp
+++ b/libc/test/src/sys/socket/linux/bind_test.cpp
@@ -14,6 +14,7 @@
#include "src/stdio/remove.h"
#include "src/unistd/close.h"
+#include "src/__support/CPP/scope.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@@ -29,6 +30,8 @@ TEST_F(LlvmLibcBindTest, BindLocalSocket) {
int sock = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_DGRAM, 0);
ASSERT_GE(sock, 0);
ASSERT_ERRNO_SUCCESS();
+ LIBC_NAMESPACE::cpp::scope_exit close_sock(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0)); });
struct sockaddr_un my_addr;
@@ -49,6 +52,5 @@ TEST_F(LlvmLibcBindTest, BindLocalSocket) {
LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),
sizeof(struct sockaddr_un)),
Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::remove(SOCK_PATH), Succeeds(0));
}
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 b95992d030324..49c84e8cf7a47 100644
--- a/libc/test/src/sys/socket/linux/connect_accept_test.cpp
+++ b/libc/test/src/sys/socket/linux/connect_accept_test.cpp
@@ -20,6 +20,7 @@
#include "src/string/strncpy.h"
#include "src/unistd/close.h"
+#include "src/__support/CPP/scope.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@@ -27,6 +28,7 @@
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
using LlvmLibcConnectAcceptTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
constexpr size_t MAX_SOCKET_PATH =
sizeof(struct sockaddr_un) - sizeof(sa_family_t);
@@ -54,51 +56,65 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
int accepting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
ASSERT_GE(accepting_socket, 0);
ASSERT_ERRNO_SUCCESS();
+ scope_exit close_accepting_socket([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(accepting_socket), Succeeds(0));
+ });
ASSERT_THAT(LIBC_NAMESPACE::bind(
accepting_socket,
reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
sizeof(struct sockaddr_un)),
Succeeds(0));
-
- int connecting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
- ASSERT_GE(connecting_socket, 0);
- ASSERT_ERRNO_SUCCESS();
-
- // These should fail as the other side is not listen()ing yet.
- ASSERT_THAT(LIBC_NAMESPACE::accept(accepting_socket, nullptr, nullptr),
- Fails(EINVAL));
- ASSERT_THAT(LIBC_NAMESPACE::connect(
- connecting_socket,
- reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
- sizeof(struct sockaddr_un)),
- Fails(ECONNREFUSED));
-
- ASSERT_THAT(LIBC_NAMESPACE::listen(accepting_socket, 1), Succeeds(0));
-
- ASSERT_THAT(LIBC_NAMESPACE::connect(
- connecting_socket,
- reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
- sizeof(struct sockaddr_un)),
- Succeeds(0));
-
- int accepted_socket =
- LIBC_NAMESPACE::accept(accepting_socket, nullptr, nullptr);
- ASSERT_GE(accepted_socket, 0);
- ASSERT_ERRNO_SUCCESS();
- ASSERT_THAT(LIBC_NAMESPACE::close(accepted_socket), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::close(connecting_socket), Succeeds(0));
+ scope_exit remove_accept_path(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::remove(ACCEPT_PATH), Succeeds(0)); });
+
+ {
+ int connecting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
+ ASSERT_GE(connecting_socket, 0);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit close_connecting_socket([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(connecting_socket), Succeeds(0));
+ });
+
+ // These should fail as the other side is not listen()ing yet.
+ ASSERT_THAT(LIBC_NAMESPACE::accept(accepting_socket, nullptr, nullptr),
+ Fails(EINVAL));
+ ASSERT_THAT(LIBC_NAMESPACE::connect(
+ connecting_socket,
+ reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+ sizeof(struct sockaddr_un)),
+ Fails(ECONNREFUSED));
+
+ ASSERT_THAT(LIBC_NAMESPACE::listen(accepting_socket, 1), Succeeds(0));
+
+ ASSERT_THAT(LIBC_NAMESPACE::connect(
+ connecting_socket,
+ reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+ sizeof(struct sockaddr_un)),
+ Succeeds(0));
+
+ int accepted_socket =
+ LIBC_NAMESPACE::accept(accepting_socket, nullptr, nullptr);
+ ASSERT_GE(accepted_socket, 0);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(accepted_socket), Succeeds(0));
+ }
// Now try connecting again, but pass a non-nullptr address to accept().
- connecting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
+ int connecting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
ASSERT_GE(connecting_socket, 0);
ASSERT_ERRNO_SUCCESS();
+ scope_exit close_connecting_socket([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(connecting_socket), Succeeds(0));
+ });
ASSERT_THAT(LIBC_NAMESPACE::bind(
connecting_socket,
reinterpret_cast<const struct sockaddr *>(&CONNECT_ADDR),
sizeof(struct sockaddr_un)),
Succeeds(0));
+ scope_exit remove_connect_path(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::remove(CONNECT_PATH), Succeeds(0)); });
ASSERT_THAT(LIBC_NAMESPACE::connect(
connecting_socket,
@@ -108,7 +124,7 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
struct sockaddr_un accepted_addr;
socklen_t accepted_addr_len = sizeof(accepted_addr);
- accepted_socket = LIBC_NAMESPACE::accept(
+ int accepted_socket = LIBC_NAMESPACE::accept(
accepting_socket, reinterpret_cast<struct sockaddr *>(&accepted_addr),
&accepted_addr_len);
ASSERT_GE(accepted_socket, 0);
@@ -117,9 +133,4 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
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::close(accepting_socket), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::close(connecting_socket), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::remove(ACCEPT_PATH), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::remove(CONNECT_PATH), 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..8d9646574b1af 100644
--- a/libc/test/src/sys/socket/linux/listen_test.cpp
+++ b/libc/test/src/sys/socket/linux/listen_test.cpp
@@ -15,6 +15,7 @@
#include "src/stdio/remove.h"
#include "src/unistd/close.h"
+#include "src/__support/CPP/scope.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@@ -22,6 +23,7 @@
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
using LlvmLibcListenTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
TEST_F(LlvmLibcListenTest, ListenLocalSocket) {
@@ -31,6 +33,8 @@ TEST_F(LlvmLibcListenTest, ListenLocalSocket) {
int sock = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
ASSERT_GE(sock, 0);
ASSERT_ERRNO_SUCCESS();
+ scope_exit close_sock(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0)); });
struct sockaddr_un my_addr;
@@ -47,11 +51,10 @@ TEST_F(LlvmLibcListenTest, ListenLocalSocket) {
LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),
sizeof(struct sockaddr_un)),
Succeeds(0));
+ scope_exit remove_sock_path(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::remove(SOCK_PATH), Succeeds(0)); });
ASSERT_THAT(LIBC_NAMESPACE::listen(sock, 5), Succeeds(0));
-
- ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::remove(SOCK_PATH), Succeeds(0));
}
TEST_F(LlvmLibcListenTest, ListenFails) {
diff --git a/libc/test/src/sys/socket/linux/send_recv_test.cpp b/libc/test/src/sys/socket/linux/send_recv_test.cpp
index a5a9b29228ece..eda61de8f73db 100644
--- a/libc/test/src/sys/socket/linux/send_recv_test.cpp
+++ b/libc/test/src/sys/socket/linux/send_recv_test.cpp
@@ -12,6 +12,7 @@
#include "src/unistd/close.h"
+#include "src/__support/CPP/scope.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@@ -30,6 +31,10 @@ TEST_F(LlvmLibcSendRecvTest, SucceedsWithSocketPair) {
ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair),
Succeeds(0));
+ LIBC_NAMESPACE::cpp::scope_exit close_sockpair([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
+ });
ASSERT_THAT(LIBC_NAMESPACE::send(sockpair[0], TEST_MESSAGE, MESSAGE_LEN, 0),
Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
@@ -40,10 +45,6 @@ TEST_F(LlvmLibcSendRecvTest, SucceedsWithSocketPair) {
Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
ASSERT_STREQ(buffer, TEST_MESSAGE);
-
- // close both ends of the socket
- ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
}
TEST_F(LlvmLibcSendRecvTest, SendFails) {
diff --git a/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp b/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp
index ae0d0557573ea..c33048122e246 100644
--- a/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp
+++ b/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp
@@ -12,6 +12,7 @@
#include "src/unistd/close.h"
+#include "src/__support/CPP/scope.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@@ -30,6 +31,10 @@ TEST_F(LlvmLibcSendMsgRecvMsgTest, SucceedsWithSocketPair) {
ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair),
Succeeds(0));
+ LIBC_NAMESPACE::cpp::scope_exit close_sockpair([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
+ });
iovec send_msg_text;
send_msg_text.iov_base =
@@ -67,10 +72,6 @@ TEST_F(LlvmLibcSendMsgRecvMsgTest, SucceedsWithSocketPair) {
Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
ASSERT_STREQ(buffer, TEST_MESSAGE);
-
- // close both ends of the socket
- ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
}
TEST_F(LlvmLibcSendMsgRecvMsgTest, SendFails) {
diff --git a/libc/test/src/sys/socket/linux/sendto_recvfrom_test.cpp b/libc/test/src/sys/socket/linux/sendto_recvfrom_test.cpp
index cd718fecef485..e10e572159a8c 100644
--- a/libc/test/src/sys/socket/linux/sendto_recvfrom_test.cpp
+++ b/libc/test/src/sys/socket/linux/sendto_recvfrom_test.cpp
@@ -12,6 +12,7 @@
#include "src/unistd/close.h"
+#include "src/__support/CPP/scope.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@@ -30,6 +31,10 @@ TEST_F(LlvmLibcSendToRecvFromTest, SucceedsWithSocketPair) {
ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair),
Succeeds(0));
+ LIBC_NAMESPACE::cpp::scope_exit close_sockpair([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
+ });
ASSERT_THAT(LIBC_NAMESPACE::sendto(sockpair[0], TEST_MESSAGE, MESSAGE_LEN, 0,
nullptr, 0),
@@ -42,10 +47,6 @@ TEST_F(LlvmLibcSendToRecvFromTest, SucceedsWithSocketPair) {
Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
ASSERT_STREQ(buffer, TEST_MESSAGE);
-
- // close both ends of the socket
- ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
}
TEST_F(LlvmLibcSendToRecvFromTest, SendToFails) {
diff --git a/libc/test/src/sys/socket/linux/socketopt_test.cpp b/libc/test/src/sys/socket/linux/socketopt_test.cpp
index 67feef4670b0a..23bdc107b5085 100644
--- a/libc/test/src/sys/socket/linux/socketopt_test.cpp
+++ b/libc/test/src/sys/socket/linux/socketopt_test.cpp
@@ -14,6 +14,7 @@
#include "src/unistd/close.h"
#include "src/unistd/pipe.h"
+#include "src/__support/CPP/scope.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@@ -22,10 +23,13 @@
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
using LlvmLibcSocketOptTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
TEST_F(LlvmLibcSocketOptTest, BasicSocketOpt) {
int sock = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
ASSERT_GE(sock, 0);
+ scope_exit close_sock(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0)); });
int optval = 0;
socklen_t optlen = sizeof(optval);
@@ -54,13 +58,13 @@ TEST_F(LlvmLibcSocketOptTest, BasicSocketOpt) {
ASSERT_THAT(
LIBC_NAMESPACE::setsockopt(sock, SOL_SOCKET, SO_TYPE, &optval, optlen),
Fails(ENOPROTOOPT));
-
- ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0));
}
TEST_F(LlvmLibcSocketOptTest, NotASocket) {
int fds[2];
ASSERT_THAT(LIBC_NAMESPACE::pipe(fds), Succeeds(0));
+ scope_exit close_fd0(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::close(fds[0]), Succeeds(0)); });
ASSERT_THAT(LIBC_NAMESPACE::close(fds[1]), Succeeds(0));
int optval = 1;
@@ -72,7 +76,6 @@ TEST_F(LlvmLibcSocketOptTest, NotASocket) {
ASSERT_THAT(LIBC_NAMESPACE::getsockopt(fds[0], SOL_SOCKET, SO_KEEPALIVE,
&optval, &optlen),
Fails(ENOTSOCK));
- ASSERT_THAT(LIBC_NAMESPACE::close(fds[0]), Succeeds(0));
}
TEST_F(LlvmLibcSocketOptTest, InvalidSocket) {
>From d6ad626eb49a5ead3be0e7928ae47c390dc7a6a0 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Tue, 28 Apr 2026 08:56:19 +0000
Subject: [PATCH 2/2] add comment
---
libc/src/__support/CPP/scope.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/libc/src/__support/CPP/scope.h b/libc/src/__support/CPP/scope.h
index 38f9dae20035e..95abc969883ba 100644
--- a/libc/src/__support/CPP/scope.h
+++ b/libc/src/__support/CPP/scope.h
@@ -1,4 +1,4 @@
-//===-- Standalone implementation of experimental/scope_exit ----*- C++ -*-===//
+//===-- Standalone implementation of experimental/scope ---------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -17,6 +17,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace cpp {
+// A reimplementation of std::experimental::scope_exit from the C++ library
+// fundamentals TS v3
template <typename EF> class scope_exit {
EF exit_function;
bool execute_on_destruction;
More information about the libc-commits
mailing list