From fc2c8b2371d7c3ef7c0ed348598abadcfdfcd467 Mon Sep 17 00:00:00 2001 From: Alex Brachet Date: Wed, 18 May 2022 17:45:05 +0000 Subject: [PATCH] [libc] Add strlcpy Differential Revision: https://reviews.llvm.org/D125806 --- libc/config/darwin/arm/entrypoints.txt | 1 + libc/config/linux/aarch64/entrypoints.txt | 1 + libc/config/linux/api.td | 1 + libc/config/linux/x86_64/entrypoints.txt | 1 + libc/config/windows/entrypoints.txt | 1 + libc/spec/bsd_ext.td | 15 +++++++++++ libc/src/string/CMakeLists.txt | 13 ++++++++++ libc/src/string/strlcpy.cpp | 31 +++++++++++++++++++++++ libc/src/string/strlcpy.h | 20 +++++++++++++++ libc/test/src/string/CMakeLists.txt | 10 ++++++++ libc/test/src/string/strlcpy_test.cpp | 30 ++++++++++++++++++++++ 11 files changed, 124 insertions(+) create mode 100644 libc/spec/bsd_ext.td create mode 100644 libc/src/string/strlcpy.cpp create mode 100644 libc/src/string/strlcpy.h create mode 100644 libc/test/src/string/strlcpy_test.cpp diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt index b2458ef8fc0f..568a8fb119de 100644 --- a/libc/config/darwin/arm/entrypoints.txt +++ b/libc/config/darwin/arm/entrypoints.txt @@ -35,6 +35,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.string.strcmp libc.src.string.strcpy libc.src.string.strcspn + libc.src.string.strlcpy libc.src.string.strlen libc.src.string.strncat libc.src.string.strncmp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 1b17b76c979d..31a596928481 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -40,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.string.strcmp libc.src.string.strcpy libc.src.string.strcspn + libc.src.string.strlcpy libc.src.string.strlen libc.src.string.strncat libc.src.string.strncmp diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td index 5d65a3c58a64..c99e35e5f2f2 100644 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -1,5 +1,6 @@ include "config/public_api.td" +include "spec/bsd_ext.td" include "spec/gnu_ext.td" include "spec/linux.td" include "spec/llvm_libc_ext.td" diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index da2e77e6516d..783dabf9a8f0 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -40,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.string.strcmp libc.src.string.strcpy libc.src.string.strcspn + libc.src.string.strlcpy libc.src.string.strlen libc.src.string.strncat libc.src.string.strncmp diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt index 89f57ef6662f..0f5b14a6e3c2 100644 --- a/libc/config/windows/entrypoints.txt +++ b/libc/config/windows/entrypoints.txt @@ -35,6 +35,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.string.strcmp libc.src.string.strcpy libc.src.string.strcspn + libc.src.string.strlcpy libc.src.string.strlen libc.src.string.strncat libc.src.string.strncmp diff --git a/libc/spec/bsd_ext.td b/libc/spec/bsd_ext.td new file mode 100644 index 000000000000..ea3f3068b672 --- /dev/null +++ b/libc/spec/bsd_ext.td @@ -0,0 +1,15 @@ +def BsdExtensions : StandardSpec<"BSDExtensions"> { + HeaderSpec String = HeaderSpec< + "string.h", + [], // Macros + [], // Types + [], // Enumerations + [ + FunctionSpec< + "strlcpy", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, + ] + >; +} diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt index b763bda47cbb..8c404064a2a9 100644 --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -126,6 +126,19 @@ add_entrypoint_object( libc.include.stdlib ) +add_entrypoint_object( + strlcpy + SRCS + strlcpy.cpp + HDRS + strlcpy.h + DEPENDS + .memory_utils.memcpy_implementation + .memory_utils.memset_implementation + .string_utils + libc.include.string +) + add_entrypoint_object( strlen SRCS diff --git a/libc/src/string/strlcpy.cpp b/libc/src/string/strlcpy.cpp new file mode 100644 index 000000000000..3cb3dd151108 --- /dev/null +++ b/libc/src/string/strlcpy.cpp @@ -0,0 +1,31 @@ +//===-- Implementation of strlcpy -----------------------------------------===// +// +// 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/string/strlcpy.h" +#include "src/string/bzero.h" +#include "src/string/memory_utils/memcpy_implementations.h" +#include "src/string/memory_utils/memset_implementations.h" +#include "src/string/string_utils.h" + +#include "src/__support/common.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(size_t, strlcpy, + (char *__restrict dst, const char *__restrict src, + size_t size)) { + size_t len = internal::string_length(src); + if (!size) + return len; + size_t n = len < size - 1 ? len : size - 1; + inline_memcpy(dst, src, n); + inline_memset(dst + n, 0, size - n); + return len; +} + +} // namespace __llvm_libc diff --git a/libc/src/string/strlcpy.h b/libc/src/string/strlcpy.h new file mode 100644 index 000000000000..f1c8e917e986 --- /dev/null +++ b/libc/src/string/strlcpy.h @@ -0,0 +1,20 @@ +//===-- Implementation header for strlcpy -----------------------*- 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_STRING_STRLCPY_H +#define LLVM_LIBC_SRC_STRING_STRLCPY_H + +#include + +namespace __llvm_libc { + +size_t strlcpy(char *__restrict dst, const char *__restrict src, size_t size); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STRING_STRLCPY_H diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt index 50e0f924a83e..5bdb47a7e672 100644 --- a/libc/test/src/string/CMakeLists.txt +++ b/libc/test/src/string/CMakeLists.txt @@ -123,6 +123,16 @@ add_libc_unittest( libc.src.string.strdup ) +add_libc_unittest( + strlcpy_test + SUITE + libc_string_unittests + SRCS + strlcpy_test.cpp + DEPENDS + libc.src.string.strlcpy +) + add_libc_unittest( strlen_test SUITE diff --git a/libc/test/src/string/strlcpy_test.cpp b/libc/test/src/string/strlcpy_test.cpp new file mode 100644 index 000000000000..1dabcfa91850 --- /dev/null +++ b/libc/test/src/string/strlcpy_test.cpp @@ -0,0 +1,30 @@ +//===-- Unittests for strlcpy ---------------------------------------------===// +// +// 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/string/strlcpy.h" +#include "utils/UnitTest/Test.h" +#include + +TEST(LlvmLibcStrlcpyTest, TooBig) { + const char *str = "abc"; + char buf[2]; + EXPECT_EQ(__llvm_libc::strlcpy(buf, str, 2), 3ul); + EXPECT_STREQ(buf, "a"); + + EXPECT_EQ(__llvm_libc::strlcpy(nullptr, str, 0), 3ul); +} + +TEST(LlvmLibcStrlcpyTest, Smaller) { + const char *str = "abc"; + char buf[7]{"111111"}; + + EXPECT_EQ(__llvm_libc::strlcpy(buf, str, 7), 3ul); + EXPECT_STREQ(buf, "abc"); + for (const char *p = buf + 3; p < buf + 7; p++) + EXPECT_EQ(*p, '\0'); +}