[libc-commits] [libc] [libc] Implement close_range in unistd (PR #236913)

Pavel Labath via libc-commits libc-commits at lists.llvm.org
Fri Oct 30 07:57:56 PDT 2026


================
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittests for close_range.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/fcntl_macros.h"
+#include "hdr/unistd_macros.h"
+#include "src/fcntl/fcntl.h"
+#include "src/unistd/close.h"
+#include "src/unistd/close_range.h"
+#include "src/unistd/pipe.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcCloseRangeTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcCloseRangeTest, InvalidArgs) {
+  // first > last should fail with EINVAL.
+  ASSERT_THAT(LIBC_NAMESPACE::close_range(10, 5, 0), Fails(EINVAL));
+
+  // Unsupported or invalid flags should fail with EINVAL.
+  ASSERT_THAT(LIBC_NAMESPACE::close_range(10, 10, ~0U), Fails(EINVAL));
+}
+
+TEST_F(LlvmLibcCloseRangeTest, ClosePipes) {
+  int fds[2];
+  ASSERT_THAT(LIBC_NAMESPACE::pipe(fds), Succeeds(0));
+
+  int min_fd = fds[0] < fds[1] ? fds[0] : fds[1];
+  int max_fd = fds[0] > fds[1] ? fds[0] : fds[1];
+
+  ASSERT_THAT(LIBC_NAMESPACE::close_range(static_cast<unsigned int>(min_fd),
+                                          static_cast<unsigned int>(max_fd), 0),
+              Succeeds(0));
+
+  // Both should now be closed.
+  ASSERT_THAT(LIBC_NAMESPACE::close(fds[0]), Fails(EBADF));
+  ASSERT_THAT(LIBC_NAMESPACE::close(fds[1]), Fails(EBADF));
+}
+
+TEST_F(LlvmLibcCloseRangeTest, CloexecFlag) {
+#ifdef CLOSE_RANGE_CLOEXEC
+  int fds[2];
+  ASSERT_THAT(LIBC_NAMESPACE::pipe(fds), Succeeds(0));
+
+  int min_fd = fds[0] < fds[1] ? fds[0] : fds[1];
+  int max_fd = fds[0] > fds[1] ? fds[0] : fds[1];
+
+  ASSERT_THAT(LIBC_NAMESPACE::close_range(static_cast<unsigned int>(min_fd),
+                                          static_cast<unsigned int>(max_fd),
+                                          CLOSE_RANGE_CLOEXEC),
+              Succeeds(0));
+
+  // Descriptors should remain open and have FD_CLOEXEC set.
+  int flags0 = LIBC_NAMESPACE::fcntl(fds[0], F_GETFD);
+  ASSERT_GT(flags0, -1);
+  EXPECT_NE(flags0 & FD_CLOEXEC, 0);
+
+  int flags1 = LIBC_NAMESPACE::fcntl(fds[1], F_GETFD);
+  ASSERT_GT(flags1, -1);
+  EXPECT_NE(flags1 & FD_CLOEXEC, 0);
+
+  EXPECT_THAT(LIBC_NAMESPACE::close(fds[0]), Succeeds(0));
----------------
labath wrote:

Use scope_exit for these.

https://github.com/llvm/llvm-project/pull/236913


More information about the libc-commits mailing list