[libc-commits] [libc] [libc] Implement mkdtemp (PR #222106)
Jeff Bailey via libc-commits
libc-commits at lists.llvm.org
Wed Sep 9 07:08:57 PDT 2026
================
@@ -0,0 +1,181 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Tests for mkdtemp
+/// See: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdtemp.html
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/sys_stat_macros.h"
+#include "hdr/types/struct_stat.h"
+#include "hdr/unistd_macros.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/stdlib/mkdtemp.h"
+#include "src/string/strdup.h"
+#include "src/string/strlen.h"
+#include "src/sys/stat/stat.h"
+#include "src/unistd/access.h"
+#include "src/unistd/rmdir.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LIBC_NAMESPACE::cpp::string_view;
+using LlvmLibcMkdtempTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcMkdtempTest, ValidTemplate) {
+ char *tmpl = LIBC_NAMESPACE::strdup(libc_make_test_file_path("tmp_XXXXXX"));
+ ASSERT_NE(tmpl, nullptr);
+ auto cleanup = LIBC_NAMESPACE::cpp::scope_exit([&] {
+ LIBC_NAMESPACE::rmdir(tmpl);
+ ::free(tmpl);
+ });
+
+ ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
+ EXPECT_THAT(LIBC_NAMESPACE::access(tmpl, F_OK), Succeeds(0));
+
+ struct stat st;
+ ASSERT_THAT(LIBC_NAMESPACE::stat(tmpl, &st), Succeeds(0));
+ EXPECT_EQ(st.st_mode & S_IFMT, static_cast<mode_t>(S_IFDIR));
+ EXPECT_EQ(st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO),
+ static_cast<mode_t>(S_IRWXU));
+}
+
+TEST_F(LlvmLibcMkdtempTest, TemplateModifiedInPlace) {
+ char *tmpl = LIBC_NAMESPACE::strdup(libc_make_test_file_path("tmp_XXXXXX"));
+ ASSERT_NE(tmpl, nullptr);
+ char *orig = LIBC_NAMESPACE::strdup(tmpl);
+ ASSERT_NE(orig, nullptr);
+ auto cleanup = LIBC_NAMESPACE::cpp::scope_exit([&] {
+ LIBC_NAMESPACE::rmdir(tmpl);
+ ::free(tmpl);
+ ::free(orig);
+ });
+
+ size_t len = LIBC_NAMESPACE::strlen(tmpl);
+ ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
+
+ EXPECT_EQ(string_view(tmpl, len - 6), string_view(orig, len - 6));
+ EXPECT_NE(string_view(tmpl + len - 6, 6), string_view("XXXXXX"));
+}
+
+TEST_F(LlvmLibcMkdtempTest, AllCharactersInCharset) {
+ char *tmpl = LIBC_NAMESPACE::strdup(libc_make_test_file_path("tmp_XXXXXX"));
+ ASSERT_NE(tmpl, nullptr);
+ auto cleanup = LIBC_NAMESPACE::cpp::scope_exit([&] {
+ LIBC_NAMESPACE::rmdir(tmpl);
+ ::free(tmpl);
+ });
+
+ size_t len = LIBC_NAMESPACE::strlen(tmpl);
+ ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
+
+ // POSIX portable filename character set, sorted by ASCII value.
+ // See
+ // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap03.html#tag_03_265
+ constexpr string_view CHARSET = "-._0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+ for (char c : string_view(tmpl + len - 6, 6))
+ EXPECT_NE(CHARSET.find_first_of(c), string_view::npos);
+}
+
+TEST_F(LlvmLibcMkdtempTest, Uniqueness) {
+ char *tmpl1 = LIBC_NAMESPACE::strdup(libc_make_test_file_path("tmp_XXXXXX"));
+ char *tmpl2 = LIBC_NAMESPACE::strdup(libc_make_test_file_path("tmp_XXXXXX"));
+ ASSERT_NE(tmpl1, nullptr);
+ ASSERT_NE(tmpl2, nullptr);
+ auto cleanup1 = LIBC_NAMESPACE::cpp::scope_exit([&] {
+ LIBC_NAMESPACE::rmdir(tmpl1);
+ ::free(tmpl1);
+ });
+ auto cleanup2 = LIBC_NAMESPACE::cpp::scope_exit([&] {
+ LIBC_NAMESPACE::rmdir(tmpl2);
+ ::free(tmpl2);
+ });
----------------
kaladron wrote:
I have them separate because the cleanup is scheduled immediately after a resource is booked. If I do both first and then do the cleanup after, if the second strdup fails then the test will fail before the cleanup has been scheduled.
https://github.com/llvm/llvm-project/pull/222106
More information about the libc-commits
mailing list