From f26c0d00df97c3b3ffce1047e92acfcbc680845b Mon Sep 17 00:00:00 2001 From: Uzair Nawaz Date: Thu, 24 Jul 2025 11:29:40 -0700 Subject: [PATCH] [libc] Implemented wcsdup libc function (#150453) Implemented wcsdup by templating internal strdup function --- libc/config/linux/x86_64/entrypoints.txt | 1 + libc/include/wchar.yaml | 6 +++ libc/src/string/allocating_string_utils.h | 6 +-- libc/src/wchar/CMakeLists.txt | 13 ++++++ libc/src/wchar/wcsdup.cpp | 27 +++++++++++++ libc/src/wchar/wcsdup.h | 21 ++++++++++ libc/test/src/wchar/CMakeLists.txt | 11 ++++++ libc/test/src/wchar/wcsdup_test.cpp | 48 +++++++++++++++++++++++ 8 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 libc/src/wchar/wcsdup.cpp create mode 100644 libc/src/wchar/wcsdup.h create mode 100644 libc/test/src/wchar/wcsdup_test.cpp diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 3cb1c483cea9..1451bd286d8a 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -377,6 +377,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.wchar.wcsrchr libc.src.wchar.wcsspn libc.src.wchar.wcscspn + libc.src.wchar.wcsdup libc.src.wchar.wmemcmp libc.src.wchar.wmempcpy libc.src.wchar.wmemcpy diff --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml index 4adf596abe65..daf05cdcd00c 100644 --- a/libc/include/wchar.yaml +++ b/libc/include/wchar.yaml @@ -226,6 +226,12 @@ functions: arguments: - type: wchar_t *__restrict - type: const wchar_t *__restrict + - name: wcsdup + standards: + - stdc + return_type: wchar_t * + arguments: + - type: const wchar_t * - name: wcslcpy standards: - stdc diff --git a/libc/src/string/allocating_string_utils.h b/libc/src/string/allocating_string_utils.h index 1dece510e796..e2f61f77b0c7 100644 --- a/libc/src/string/allocating_string_utils.h +++ b/libc/src/string/allocating_string_utils.h @@ -20,15 +20,15 @@ namespace LIBC_NAMESPACE_DECL { namespace internal { -LIBC_INLINE cpp::optional strdup(const char *src) { +template LIBC_INLINE cpp::optional strdup(const T *src) { if (src == nullptr) return cpp::nullopt; size_t len = string_length(src) + 1; AllocChecker ac; - char *newstr = new (ac) char[len]; + T *newstr = new (ac) T[len]; if (!ac) return cpp::nullopt; - inline_memcpy(newstr, src, len); + inline_memcpy(newstr, src, len * sizeof(T)); return newstr; } diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt index 2b95d94e4230..25319837bdc7 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -255,6 +255,19 @@ add_entrypoint_object( libc.hdr.wchar_macros ) +add_entrypoint_object( + wcsdup + SRCS + wcsdup.cpp + HDRS + wcsdup.h + DEPENDS + libc.hdr.types.wchar_t + libc.src.__support.libc_errno + libc.src.__support.macros.config + libc.src.string.allocating_string_utils +) + add_entrypoint_object( wcspbrk SRCS diff --git a/libc/src/wchar/wcsdup.cpp b/libc/src/wchar/wcsdup.cpp new file mode 100644 index 000000000000..d4a13d35e4d5 --- /dev/null +++ b/libc/src/wchar/wcsdup.cpp @@ -0,0 +1,27 @@ +//===-- Implementation of wcsdup -----------------------------------------===// +// +// 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/wchar/wcsdup.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/string/allocating_string_utils.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(wchar_t *, wcsdup, (const wchar_t *wcs)) { + auto dup = internal::strdup(wcs); + if (dup) + return *dup; + if (wcs != nullptr) + libc_errno = ENOMEM; + return nullptr; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/wcsdup.h b/libc/src/wchar/wcsdup.h new file mode 100644 index 000000000000..80b3e52d71b9 --- /dev/null +++ b/libc/src/wchar/wcsdup.h @@ -0,0 +1,21 @@ +//===-- Implementation header for wcsdup ----------------------------------===// +// +// 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_WCHAR_WCSDUP_H +#define LLVM_LIBC_SRC_WCHAR_WCSDUP_H + +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +wchar_t *wcsdup(const wchar_t *wcs); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSDUP_H diff --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt index baa52b74c3d9..9b0c63ad8e07 100644 --- a/libc/test/src/wchar/CMakeLists.txt +++ b/libc/test/src/wchar/CMakeLists.txt @@ -24,6 +24,17 @@ add_libc_test( libc.src.wchar.wcsnlen ) +add_libc_test( + wcsdup_test + SUITE + libc_wchar_unittests + SRCS + wcsdup_test.cpp + DEPENDS + libc.hdr.types.wchar_t + libc.src.wchar.wcsdup +) + add_libc_test( btowc_test SUITE diff --git a/libc/test/src/wchar/wcsdup_test.cpp b/libc/test/src/wchar/wcsdup_test.cpp new file mode 100644 index 000000000000..eafbb2d2b64e --- /dev/null +++ b/libc/test/src/wchar/wcsdup_test.cpp @@ -0,0 +1,48 @@ +//===-- Unittests for wcsdup ----------------------------------------------===// +// +// 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 "hdr/types/wchar_t.h" +#include "src/wchar/wcsdup.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcWcsDupTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcWcsDupTest, EmptyString) { + const wchar_t *empty = L""; + + wchar_t *result = LIBC_NAMESPACE::wcsdup(empty); + ASSERT_ERRNO_SUCCESS(); + + ASSERT_NE(result, static_cast(nullptr)); + ASSERT_NE(empty, const_cast(result)); + ASSERT_TRUE(empty[0] == result[0]); + ::free(result); +} + +TEST_F(LlvmLibcWcsDupTest, AnyString) { + const wchar_t *abc = L"abc"; + + wchar_t *result = LIBC_NAMESPACE::wcsdup(abc); + ASSERT_ERRNO_SUCCESS(); + + ASSERT_NE(result, static_cast(nullptr)); + ASSERT_NE(abc, const_cast(result)); + ASSERT_TRUE(abc[0] == result[0]); + ASSERT_TRUE(abc[1] == result[1]); + ASSERT_TRUE(abc[2] == result[2]); + ASSERT_TRUE(abc[3] == result[3]); + ::free(result); +} + +TEST_F(LlvmLibcWcsDupTest, NullPtr) { + wchar_t *result = LIBC_NAMESPACE::wcsdup(nullptr); + ASSERT_ERRNO_SUCCESS(); + + ASSERT_EQ(result, static_cast(nullptr)); +}