[libc-commits] [libc] [libc] Use scope_exit to clean up resources in tests (PR #196120)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Wed May 6 10:13:50 PDT 2026
https://github.com/labath created https://github.com/llvm/llvm-project/pull/196120
Simplify socket and FILE unit tests by using the `scope_exit` helper to automatically clean up resources (sockets and FILE pointers), preventing leaks on test failures.
Assisted by Gemini.
>From 5904923e1edd07913f5a5b63a02a67c21602d1cd Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 6 May 2026 09:59:54 +0000
Subject: [PATCH] [libc] Use scope_exit to clean up resources in tests
Simplify socket and FILE unit tests by using the `scope_exit` helper to
automatically clean up resources (sockets and FILE pointers), preventing leaks
on test failures.
---
libc/test/src/stdio/CMakeLists.txt | 5 +
libc/test/src/stdio/fgetc_test.cpp | 48 ++++---
libc/test/src/stdio/fgetc_unlocked_test.cpp | 53 ++++----
libc/test/src/stdio/fgets_test.cpp | 122 ++++++++++--------
libc/test/src/stdio/fopen_test.cpp | 47 ++++---
libc/test/src/stdio/rewind_test.cpp | 85 ++++++------
libc/test/src/sys/socket/linux/CMakeLists.txt | 1 +
.../src/sys/socket/linux/shutdown_test.cpp | 23 ++--
8 files changed, 216 insertions(+), 168 deletions(-)
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index f5eb5c81f90e1..9737dcba7f904 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -31,6 +31,7 @@ add_libc_test(
rewind_test.cpp
DEPENDS
libc.include.stdio
+ libc.src.__support.CPP.scope
libc.src.stdio.fclose
libc.src.stdio.ferror
libc.src.stdio.fopen
@@ -437,6 +438,7 @@ add_libc_test(
SRCS
fopen_test.cpp
DEPENDS
+ libc.src.__support.CPP.scope
libc.src.stdio.fread
libc.src.stdio.fwrite
libc.src.stdio.fclose
@@ -519,6 +521,7 @@ add_libc_test(
fgetc_test.cpp
DEPENDS
libc.include.stdio
+ libc.src.__support.CPP.scope
libc.src.errno.errno
libc.src.stdio.fclose
libc.src.stdio.feof
@@ -539,6 +542,7 @@ add_libc_test(
fgetc_unlocked_test.cpp
DEPENDS
libc.include.stdio
+ libc.src.__support.CPP.scope
libc.src.errno.errno
libc.src.stdio.fclose
libc.src.stdio.ferror
@@ -563,6 +567,7 @@ add_libc_test(
fgets_test.cpp
DEPENDS
libc.include.stdio
+ libc.src.__support.CPP.scope
libc.src.errno.errno
libc.src.stdio.fclose
libc.src.stdio.feof
diff --git a/libc/test/src/stdio/fgetc_test.cpp b/libc/test/src/stdio/fgetc_test.cpp
index 1d242a0475aba..f880ba499d3ab 100644
--- a/libc/test/src/stdio/fgetc_test.cpp
+++ b/libc/test/src/stdio/fgetc_test.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "src/__support/CPP/scope.h"
#include "src/stdio/clearerr.h"
#include "src/stdio/fclose.h"
#include "src/stdio/feof.h"
@@ -21,37 +22,44 @@
#include "hdr/stdio_macros.h"
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LIBC_NAMESPACE::cpp::scope_exit;
class LlvmLibcGetcTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest {
public:
using GetcFunc = int(FILE *);
void test_with_func(GetcFunc *func, const char *filename) {
- ::FILE *file = LIBC_NAMESPACE::fopen(filename, "w");
- ASSERT_FALSE(file == nullptr);
constexpr char CONTENT[] = "123456789";
constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1;
- ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file),
- Succeeds(WRITE_SIZE));
- // This is a write-only file so reads should fail.
- ASSERT_THAT(func(file), Fails(EBADF, EOF));
- // This is an error and not a real EOF.
- ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0);
- ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
- ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds());
+ {
+ ::FILE *file = LIBC_NAMESPACE::fopen(filename, "w");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); });
- file = LIBC_NAMESPACE::fopen(filename, "r");
- ASSERT_FALSE(file == nullptr);
-
- for (size_t i = 0; i < WRITE_SIZE; ++i) {
- ASSERT_THAT(func(file), Succeeds(int('1' + i)));
+ ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file),
+ Succeeds(WRITE_SIZE));
+ // This is a write-only file so reads should fail.
+ ASSERT_THAT(func(file), Fails(EBADF, EOF));
+ // This is an error and not a real EOF.
+ ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0);
+ ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
}
- // Reading more should return EOF but not set error.
- ASSERT_THAT(func(file), Succeeds(EOF));
- ASSERT_NE(LIBC_NAMESPACE::feof(file), 0);
- ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
- ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds());
+ {
+ ::FILE *file = LIBC_NAMESPACE::fopen(filename, "r");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); });
+
+ for (size_t i = 0; i < WRITE_SIZE; ++i) {
+ ASSERT_THAT(func(file), Succeeds(int('1' + i)));
+ }
+ // Reading more should return EOF but not set error.
+ ASSERT_THAT(func(file), Succeeds(EOF));
+ ASSERT_NE(LIBC_NAMESPACE::feof(file), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
+ }
}
};
diff --git a/libc/test/src/stdio/fgetc_unlocked_test.cpp b/libc/test/src/stdio/fgetc_unlocked_test.cpp
index 16d79211f5e8f..e3f936f48af68 100644
--- a/libc/test/src/stdio/fgetc_unlocked_test.cpp
+++ b/libc/test/src/stdio/fgetc_unlocked_test.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "src/__support/CPP/scope.h"
#include "src/stdio/fclose.h"
#include "src/stdio/feof.h"
#include "src/stdio/feof_unlocked.h"
@@ -24,39 +25,47 @@
#include "hdr/stdio_macros.h"
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LIBC_NAMESPACE::cpp::scope_exit;
class LlvmLibcGetcTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest {
public:
using GetcFunc = int(FILE *);
void test_with_func(GetcFunc *func, const char *filename) {
- ::FILE *file = LIBC_NAMESPACE::fopen(filename, "w");
- ASSERT_FALSE(file == nullptr);
constexpr char CONTENT[] = "123456789";
constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1;
- ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file),
- Succeeds(WRITE_SIZE));
- // This is a write-only file so reads should fail.
- ASSERT_THAT(func(file), Fails(EBADF, EOF));
- // This is an error and not a real EOF.
- ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0);
- ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
- ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds());
+ {
+ ::FILE *file = LIBC_NAMESPACE::fopen(filename, "w");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); });
- file = LIBC_NAMESPACE::fopen(filename, "r");
- ASSERT_FALSE(file == nullptr);
-
- LIBC_NAMESPACE::flockfile(file);
- for (size_t i = 0; i < WRITE_SIZE; ++i) {
- ASSERT_THAT(func(file), Succeeds(int('1' + i)));
+ ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file),
+ Succeeds(WRITE_SIZE));
+ // This is a write-only file so reads should fail.
+ ASSERT_THAT(func(file), Fails(EBADF, EOF));
+ // This is an error and not a real EOF.
+ ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0);
+ ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
}
- // Reading more should return EOF but not set error.
- ASSERT_THAT(func(file), Succeeds(EOF));
- ASSERT_NE(LIBC_NAMESPACE::feof_unlocked(file), 0);
- ASSERT_EQ(LIBC_NAMESPACE::ferror_unlocked(file), 0);
- LIBC_NAMESPACE::funlockfile(file);
- ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds());
+ {
+ ::FILE *file = LIBC_NAMESPACE::fopen(filename, "r");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); });
+
+ LIBC_NAMESPACE::flockfile(file);
+ scope_exit unlock_file([&] { LIBC_NAMESPACE::funlockfile(file); });
+
+ for (size_t i = 0; i < WRITE_SIZE; ++i) {
+ ASSERT_THAT(func(file), Succeeds(int('1' + i)));
+ }
+ // Reading more should return EOF but not set error.
+ ASSERT_THAT(func(file), Succeeds(EOF));
+ ASSERT_NE(LIBC_NAMESPACE::feof_unlocked(file), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::ferror_unlocked(file), 0);
+ }
}
};
diff --git a/libc/test/src/stdio/fgets_test.cpp b/libc/test/src/stdio/fgets_test.cpp
index 14f054eee1339..41b0a9291e29c 100644
--- a/libc/test/src/stdio/fgets_test.cpp
+++ b/libc/test/src/stdio/fgets_test.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "src/__support/CPP/scope.h"
#include "src/stdio/fclose.h"
#include "src/stdio/feof.h"
#include "src/stdio/ferror.h"
@@ -18,78 +19,85 @@
using LlvmLibcFgetsTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LIBC_NAMESPACE::cpp::scope_exit;
TEST_F(LlvmLibcFgetsTest, WriteAndReadCharacters) {
constexpr char FILENAME[] = APPEND_LIBC_TEST("testdata/fgets.test");
- ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w");
- ASSERT_FALSE(file == nullptr);
- constexpr char CONTENT[] = "123456789\n"
- "1234567\n"
- "123456\n"
- "1";
- constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1;
-
char buff[8];
char *output;
- ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file),
- Succeeds(WRITE_SIZE));
- // This is a write-only file so reads should fail.
- ASSERT_THAT(LIBC_NAMESPACE::fgets(buff, 8, file),
- Fails(EBADF, static_cast<char *>(nullptr)));
- // This is an error and not a real EOF.
- ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0);
- ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
-
- ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds());
+ {
+ ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); });
+
+ constexpr char CONTENT[] = "123456789\n"
+ "1234567\n"
+ "123456\n"
+ "1";
+ constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1;
+
+ ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file),
+ Succeeds(WRITE_SIZE));
+ // This is a write-only file so reads should fail.
+ ASSERT_THAT(LIBC_NAMESPACE::fgets(buff, 8, file),
+ Fails(EBADF, static_cast<char *>(nullptr)));
+ // This is an error and not a real EOF.
+ ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0);
+ ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
+ }
- file = LIBC_NAMESPACE::fopen(FILENAME, "r");
- ASSERT_FALSE(file == nullptr);
+ {
+ ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "r");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds()); });
- // The GPU build relies on the host C library, so this check may be different.
+ // The GPU build relies on the host C library, so this check may be
+ // different.
#ifndef LIBC_TARGET_ARCH_IS_GPU
- // If we request just 1 byte, it should return just a null byte and not
- // advance the read head. This is implementation defined.
- output = LIBC_NAMESPACE::fgets(buff, 1, file);
- ASSERT_TRUE(output == buff);
- ASSERT_EQ(buff[0], '\0');
- ASSERT_ERRNO_SUCCESS();
-
- // If we request less than 1 byte, it should do nothing and return nullptr.
- // This is also implementation defined.
- output = LIBC_NAMESPACE::fgets(buff, 0, file);
- ASSERT_TRUE(output == nullptr);
- ASSERT_ERRNO_SUCCESS();
+ // If we request just 1 byte, it should return just a null byte and not
+ // advance the read head. This is implementation defined.
+ output = LIBC_NAMESPACE::fgets(buff, 1, file);
+ ASSERT_TRUE(output == buff);
+ ASSERT_EQ(buff[0], '\0');
+ ASSERT_ERRNO_SUCCESS();
+
+ // If we request less than 1 byte, it should do nothing and return nullptr.
+ // This is also implementation defined.
+ output = LIBC_NAMESPACE::fgets(buff, 0, file);
+ ASSERT_TRUE(output == nullptr);
+ ASSERT_ERRNO_SUCCESS();
#endif
- const char *output_arr[] = {
- "1234567", "89\n", "1234567", "\n", "123456\n", "1",
- };
-
- constexpr size_t ARR_SIZE = sizeof(output_arr) / sizeof(char *);
+ const char *output_arr[] = {
+ "1234567", "89\n", "1234567", "\n", "123456\n", "1",
+ };
- for (size_t i = 0; i < ARR_SIZE; ++i) {
- output = LIBC_NAMESPACE::fgets(buff, 8, file);
+ constexpr size_t ARR_SIZE = sizeof(output_arr) / sizeof(char *);
- // This pointer comparison is intentional, fgets should return a pointer to
- // buff when it succeeds.
- ASSERT_TRUE(output == buff);
- ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
+ for (size_t i = 0; i < ARR_SIZE; ++i) {
+ output = LIBC_NAMESPACE::fgets(buff, 8, file);
- EXPECT_STREQ(buff, output_arr[i]);
- }
+ // This pointer comparison is intentional, fgets should return a pointer
+ // to buff when it succeeds.
+ ASSERT_TRUE(output == buff);
+ ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
- // This should have hit the end of the file, but that isn't an error unless it
- // fails to read anything.
- ASSERT_NE(LIBC_NAMESPACE::feof(file), 0);
- ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
- ASSERT_ERRNO_SUCCESS();
+ EXPECT_STREQ(buff, output_arr[i]);
+ }
- // Reading more should be an EOF, but not an error.
- output = LIBC_NAMESPACE::fgets(buff, 8, file);
- ASSERT_TRUE(output == nullptr);
- ASSERT_NE(LIBC_NAMESPACE::feof(file), 0);
- ASSERT_ERRNO_SUCCESS();
+ // This should have hit the end of the file, but that isn't an error unless
+ // it fails to read anything.
+ ASSERT_NE(LIBC_NAMESPACE::feof(file), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
+ ASSERT_ERRNO_SUCCESS();
- ASSERT_THAT(LIBC_NAMESPACE::fclose(file), Succeeds());
+ // Reading more should be an EOF, but not an error.
+ output = LIBC_NAMESPACE::fgets(buff, 8, file);
+ ASSERT_TRUE(output == nullptr);
+ ASSERT_NE(LIBC_NAMESPACE::feof(file), 0);
+ ASSERT_ERRNO_SUCCESS();
+ }
}
diff --git a/libc/test/src/stdio/fopen_test.cpp b/libc/test/src/stdio/fopen_test.cpp
index 60852ddf09388..b3b24253d1438 100644
--- a/libc/test/src/stdio/fopen_test.cpp
+++ b/libc/test/src/stdio/fopen_test.cpp
@@ -6,36 +6,41 @@
//
//===----------------------------------------------------------------------===//
+#include "src/__support/CPP/scope.h"
#include "src/__support/File/file.h"
#include "src/stdio/fclose.h"
#include "src/stdio/fopen.h"
-#include "src/stdio/fwrite.h"
#include "src/stdio/fread.h"
+#include "src/stdio/fwrite.h"
#include "test/UnitTest/Test.h"
+using LIBC_NAMESPACE::cpp::scope_exit;
+
TEST(LlvmLibcFOpenTest, PrintToFile) {
size_t result;
- FILE *file =
- LIBC_NAMESPACE::fopen(APPEND_LIBC_TEST("testdata/test.txt"), "w");
- ASSERT_FALSE(file == nullptr);
-
static constexpr char STRING[] = "A simple string written to a file\n";
- result = LIBC_NAMESPACE::fwrite(STRING, 1, sizeof(STRING) - 1, file);
- EXPECT_GE(result, size_t(0));
-
- ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
-
- FILE *new_file =
- LIBC_NAMESPACE::fopen(APPEND_LIBC_TEST("testdata/test.txt"), "r");
- ASSERT_FALSE(new_file == nullptr);
-
- static char data[64] = {0};
- ASSERT_EQ(LIBC_NAMESPACE::fread(data, 1, sizeof(STRING) - 1, new_file),
- sizeof(STRING) - 1);
- data[sizeof(STRING) - 1] = '\0';
- ASSERT_STREQ(data, STRING);
-
- ASSERT_EQ(0, LIBC_NAMESPACE::fclose(new_file));
+ {
+ FILE *file =
+ LIBC_NAMESPACE::fopen(APPEND_LIBC_TEST("testdata/test.txt"), "w");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file([&] { ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); });
+
+ result = LIBC_NAMESPACE::fwrite(STRING, 1, sizeof(STRING) - 1, file);
+ EXPECT_GE(result, size_t(0));
+ }
+
+ {
+ FILE *file =
+ LIBC_NAMESPACE::fopen(APPEND_LIBC_TEST("testdata/test.txt"), "r");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file([&] { ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); });
+
+ static char data[64] = {0};
+ ASSERT_EQ(LIBC_NAMESPACE::fread(data, 1, sizeof(STRING) - 1, file),
+ sizeof(STRING) - 1);
+ data[sizeof(STRING) - 1] = '\0';
+ ASSERT_STREQ(data, STRING);
+ }
}
diff --git a/libc/test/src/stdio/rewind_test.cpp b/libc/test/src/stdio/rewind_test.cpp
index 41dcbbdb8dd80..a86b7bfa9ea33 100644
--- a/libc/test/src/stdio/rewind_test.cpp
+++ b/libc/test/src/stdio/rewind_test.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "src/__support/CPP/scope.h"
#include "src/stdio/fclose.h"
#include "src/stdio/ferror.h"
#include "src/stdio/fopen.h"
@@ -17,60 +18,66 @@
#include "test/UnitTest/Test.h"
using LlvmLibcRewindTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
TEST_F(LlvmLibcRewindTest, WriteRewindRead) {
constexpr char FILENAME[] = APPEND_LIBC_TEST("testdata/rewind.test");
auto FILEPATH = libc_make_test_file_path(FILENAME);
- ::FILE *file = LIBC_NAMESPACE::fopen(FILEPATH, "w");
- ASSERT_FALSE(file == nullptr);
-
constexpr char FIRST_DATA[] = "123456789";
- ASSERT_THAT(LIBC_NAMESPACE::fwrite(FIRST_DATA, 1, sizeof(FIRST_DATA), file),
- Succeeds(sizeof(FIRST_DATA)));
- // File state is "123456789"
+ {
+ ::FILE *file = LIBC_NAMESPACE::fopen(FILEPATH, "w");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file([&] { ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); });
+
+ ASSERT_THAT(LIBC_NAMESPACE::fwrite(FIRST_DATA, 1, sizeof(FIRST_DATA), file),
+ Succeeds(sizeof(FIRST_DATA)));
- LIBC_NAMESPACE::rewind(file);
+ // File state is "123456789"
- // Cursor is back to the start
+ LIBC_NAMESPACE::rewind(file);
- constexpr char SECOND_DATA[] = "abc";
- ASSERT_THAT(
- LIBC_NAMESPACE::fwrite(SECOND_DATA, 1, sizeof(SECOND_DATA) - 1, file),
- Succeeds(sizeof(SECOND_DATA) - 1));
+ // Cursor is back to the start
- // File state is "abc456789"
+ constexpr char SECOND_DATA[] = "abc";
+ ASSERT_THAT(
+ LIBC_NAMESPACE::fwrite(SECOND_DATA, 1, sizeof(SECOND_DATA) - 1, file),
+ Succeeds(sizeof(SECOND_DATA) - 1));
- // attempt to read from write-only file causing error state
- char read_data[sizeof(FIRST_DATA)];
- ASSERT_EQ(LIBC_NAMESPACE::fread(read_data, 1, sizeof(read_data), file),
- size_t(0));
- ASSERT_ERRNO_FAILURE();
- ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
+ // File state is "abc456789"
- // rewind to start and check that that clears the error.
- LIBC_NAMESPACE::rewind(file);
- ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
+ // attempt to read from write-only file causing error state
+ char read_data[sizeof(FIRST_DATA)];
+ ASSERT_EQ(LIBC_NAMESPACE::fread(read_data, 1, sizeof(read_data), file),
+ size_t(0));
+ ASSERT_ERRNO_FAILURE();
+ ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
- // Close out the file and reopen in read mode.
- LIBC_NAMESPACE::fclose(file);
- file = LIBC_NAMESPACE::fopen(FILEPATH, "r");
- ASSERT_FALSE(file == nullptr);
+ // rewind to start and check that that clears the error.
+ LIBC_NAMESPACE::rewind(file);
+ ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
+ }
- // Read the file to check that it was written correctly.
- ASSERT_THAT(LIBC_NAMESPACE::fread(read_data, 1, 3, file),
- Succeeds(size_t(3)));
- read_data[3] = '\0';
- ASSERT_STREQ(read_data, "abc");
- ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
+ {
+ // Reopen the file in read mode.
+ ::FILE *file = LIBC_NAMESPACE::fopen(FILEPATH, "r");
+ ASSERT_FALSE(file == nullptr);
+ scope_exit close_file([&] { ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file)); });
- // check that rewind also works on read files.
- LIBC_NAMESPACE::rewind(file);
- ASSERT_THAT(LIBC_NAMESPACE::fread(read_data, 1, sizeof(read_data), file),
- Succeeds(sizeof(FIRST_DATA)));
- read_data[sizeof(FIRST_DATA) - 1] = '\0';
- ASSERT_STREQ(read_data, "abc456789");
+ char read_data[sizeof(FIRST_DATA)];
+ // Read the file to check that it was written correctly.
+ ASSERT_THAT(LIBC_NAMESPACE::fread(read_data, 1, 3, file),
+ Succeeds(size_t(3)));
+ read_data[3] = '\0';
+ ASSERT_STREQ(read_data, "abc");
+ ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
- LIBC_NAMESPACE::fclose(file);
+ // check that rewind also works on read files.
+ LIBC_NAMESPACE::rewind(file);
+ ASSERT_THAT(LIBC_NAMESPACE::fread(read_data, 1, sizeof(read_data), file),
+ Succeeds(sizeof(FIRST_DATA)));
+ read_data[sizeof(FIRST_DATA) - 1] = '\0';
+ ASSERT_STREQ(read_data, "abc456789");
+ }
}
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index e29140ee06b24..ae6bd9162dca8 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -208,6 +208,7 @@ add_libc_unittest(
libc.include.sys_socket
libc.hdr.sys_socket_macros
libc.hdr.types.ssize_t
+ libc.src.__support.CPP.scope
libc.src.errno.errno
libc.src.sys.socket.shutdown
libc.src.sys.socket.socketpair
diff --git a/libc/test/src/sys/socket/linux/shutdown_test.cpp b/libc/test/src/sys/socket/linux/shutdown_test.cpp
index e32ae625277b9..f351d85b3dbf3 100644
--- a/libc/test/src/sys/socket/linux/shutdown_test.cpp
+++ b/libc/test/src/sys/socket/linux/shutdown_test.cpp
@@ -8,6 +8,7 @@
#include "hdr/sys_socket_macros.h"
#include "hdr/types/ssize_t.h"
+#include "src/__support/CPP/scope.h"
#include "src/sys/socket/shutdown.h"
#include "src/sys/socket/socketpair.h"
#include "src/unistd/close.h"
@@ -20,11 +21,16 @@
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
using LlvmLibcShutdownTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
TEST_F(LlvmLibcShutdownTest, ShutWrProducesEOF) {
int sv[2];
ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sv),
Succeeds(0));
+ scope_exit close_sv([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(sv[0]), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::close(sv[1]), Succeeds(0));
+ });
// Shut down write on sv[0].
ASSERT_THAT(LIBC_NAMESPACE::shutdown(sv[0], SHUT_WR), Succeeds(0));
@@ -33,15 +39,16 @@ TEST_F(LlvmLibcShutdownTest, ShutWrProducesEOF) {
char read_buf[10];
ASSERT_THAT(LIBC_NAMESPACE::read(sv[1], read_buf, sizeof(read_buf)),
Succeeds<ssize_t>(0));
-
- ASSERT_THAT(LIBC_NAMESPACE::close(sv[0]), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::close(sv[1]), Succeeds(0));
}
TEST_F(LlvmLibcShutdownTest, ShutRdPreventsReading) {
int sv[2];
ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sv),
Succeeds(0));
+ scope_exit close_sv([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(sv[0]), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::close(sv[1]), Succeeds(0));
+ });
// Shut down read on sv[0].
ASSERT_THAT(LIBC_NAMESPACE::shutdown(sv[0], SHUT_RD), Succeeds(0));
@@ -50,15 +57,16 @@ TEST_F(LlvmLibcShutdownTest, ShutRdPreventsReading) {
char read_buf[10];
ASSERT_THAT(LIBC_NAMESPACE::read(sv[0], read_buf, sizeof(read_buf)),
Succeeds<ssize_t>(0));
-
- ASSERT_THAT(LIBC_NAMESPACE::close(sv[0]), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::close(sv[1]), Succeeds(0));
}
TEST_F(LlvmLibcShutdownTest, ShutRdWrDoesBoth) {
int sv[2];
ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sv),
Succeeds(0));
+ scope_exit close_sv([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(sv[0]), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::close(sv[1]), Succeeds(0));
+ });
// Shut down read and write on sv[0].
ASSERT_THAT(LIBC_NAMESPACE::shutdown(sv[0], SHUT_RDWR), Succeeds(0));
@@ -69,9 +77,6 @@ TEST_F(LlvmLibcShutdownTest, ShutRdWrDoesBoth) {
Succeeds<ssize_t>(0));
ASSERT_THAT(LIBC_NAMESPACE::read(sv[1], read_buf, sizeof(read_buf)),
Succeeds<ssize_t>(0));
-
- ASSERT_THAT(LIBC_NAMESPACE::close(sv[0]), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::close(sv[1]), Succeeds(0));
}
TEST_F(LlvmLibcShutdownTest, FailsOnInvalidSocket) {
More information about the libc-commits
mailing list