[libc-commits] [libc] 9b6f8b9 - [libc] add stpcpy and stpncpy

Michael Jones via libc-commits libc-commits at lists.llvm.org
Thu Nov 4 11:39:30 PDT 2021


Author: Michael Jones
Date: 2021-11-04T11:39:26-07:00
New Revision: 9b6f8b985c6a22f16a7c6a611d239198cf1d1504

URL: https://github.com/llvm/llvm-project/commit/9b6f8b985c6a22f16a7c6a611d239198cf1d1504
DIFF: https://github.com/llvm/llvm-project/commit/9b6f8b985c6a22f16a7c6a611d239198cf1d1504.diff

LOG: [libc] add stpcpy and stpncpy

Adds an implementation for stpcpy and stpncpy, which are posix extension
functions.

Reviewed By: sivachandra, lntue

Differential Revision: https://reviews.llvm.org/D111913

Added: 
    libc/src/string/stpcpy.cpp
    libc/src/string/stpcpy.h
    libc/src/string/stpncpy.cpp
    libc/src/string/stpncpy.h
    libc/test/src/string/stpcpy_test.cpp
    libc/test/src/string/stpncpy_test.cpp

Modified: 
    libc/config/linux/x86_64/entrypoints.txt
    libc/spec/posix.td
    libc/src/string/CMakeLists.txt
    libc/test/src/string/CMakeLists.txt
    libc/test/src/string/strcpy_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index bce6cbf1ee65..a757dc35b5d2 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -31,6 +31,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.mempcpy
     libc.src.string.memrchr
     libc.src.string.memset
+    libc.src.string.stpcpy
+    libc.src.string.stpncpy
     libc.src.string.strcat
     libc.src.string.strchr
     libc.src.string.strcmp

diff  --git a/libc/spec/posix.td b/libc/spec/posix.td
index 45d12fa23992..e1fc63367c6a 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -235,6 +235,19 @@ def POSIX : StandardSpec<"POSIX"> {
              ArgSpec<ConstVoidRestrictedPtr>,
              ArgSpec<SizeTType>]
         >,
+        FunctionSpec<
+            "stpcpy",
+            RetValSpec<CharPtr>,
+            [ArgSpec<RestrictedCharPtr>,
+             ArgSpec<ConstRestrictedCharPtr>]
+        >,
+        FunctionSpec<
+            "stpncpy",
+            RetValSpec<CharPtr>,
+            [ArgSpec<RestrictedCharPtr>,
+             ArgSpec<ConstRestrictedCharPtr>,
+             ArgSpec<SizeTType>]
+        >,
         FunctionSpec<
             "strnlen",
              RetValSpec<SizeTType>,

diff  --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index 5a130fc6ecc7..d5cfb1742018 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -56,6 +56,27 @@ add_entrypoint_object(
     memrchr.h
 )
 
+add_entrypoint_object(
+  stpcpy
+  SRCS
+    stpcpy.cpp
+  HDRS
+    stpcpy.h
+  DEPENDS
+    .mempcpy
+    .string_utils
+)
+
+add_entrypoint_object(
+  stpncpy
+  SRCS
+    stpncpy.cpp
+  HDRS
+    stpncpy.h
+  DEPENDS
+    .bzero
+)
+
 add_entrypoint_object(
   strcat
   SRCS

diff  --git a/libc/src/string/stpcpy.cpp b/libc/src/string/stpcpy.cpp
new file mode 100644
index 000000000000..dd48f3cfb5e8
--- /dev/null
+++ b/libc/src/string/stpcpy.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of stpcpy ------------------------------------------===//
+//
+// 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/stpcpy.h"
+#include "src/string/mempcpy.h"
+#include "src/string/string_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/sanitizer.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(char *, stpcpy,
+                   (char *__restrict dest, const char *__restrict src)) {
+  size_t size = internal::string_length(src) + 1;
+  char *result =
+      reinterpret_cast<char *>(__llvm_libc::mempcpy(dest, src, size));
+
+  if (result != nullptr)
+    return result - 1;
+  return nullptr;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/string/stpcpy.h b/libc/src/string/stpcpy.h
new file mode 100644
index 000000000000..84d5738f0e2b
--- /dev/null
+++ b/libc/src/string/stpcpy.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for stpcpy ------------------------*- 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_STPCPY_H
+#define LLVM_LIBC_SRC_STRING_STPCPY_H
+
+namespace __llvm_libc {
+
+char *stpcpy(char *__restrict dest, const char *__restrict src);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STPCPY_H

diff  --git a/libc/src/string/stpncpy.cpp b/libc/src/string/stpncpy.cpp
new file mode 100644
index 000000000000..374330ede2ca
--- /dev/null
+++ b/libc/src/string/stpncpy.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of stpncpy -----------------------------------------===//
+//
+// 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/stpncpy.h"
+#include "src/string/bzero.h"
+
+#include "src/__support/common.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(char *, stpncpy,
+                   (char *__restrict dest, const char *__restrict src,
+                    size_t n)) {
+  size_t i;
+  // Copy up until \0 is found.
+  for (i = 0; i < n && src[i] != '\0'; ++i)
+    dest[i] = src[i];
+  // When n>strlen(src), n-strlen(src) \0 are appended.
+  if (n > i)
+    __llvm_libc::bzero(dest + i, n - i);
+  return dest + i;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/string/stpncpy.h b/libc/src/string/stpncpy.h
new file mode 100644
index 000000000000..6320a290b1dd
--- /dev/null
+++ b/libc/src/string/stpncpy.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for stpncpy -----------------------*- 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_STPNCPY_H
+#define LLVM_LIBC_SRC_STRING_STPNCPY_H
+
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+char *stpncpy(char *__restrict dest, const char *__restrict src, size_t n);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STPNCPY_H

diff  --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt
index a5b931d768d3..6713bd73b724 100644
--- a/libc/test/src/string/CMakeLists.txt
+++ b/libc/test/src/string/CMakeLists.txt
@@ -42,6 +42,26 @@ add_libc_unittest(
     libc.src.string.memrchr
 )
 
+add_libc_unittest(
+  stpcpy_test
+  SUITE
+    libc_string_unittests
+  SRCS
+    stpcpy_test.cpp
+  DEPENDS
+    libc.src.string.stpcpy
+)
+
+add_libc_unittest(
+  stpncpy_test
+  SUITE
+    libc_string_unittests
+  SRCS
+    stpncpy_test.cpp
+  DEPENDS
+    libc.src.string.stpncpy
+)
+
 add_libc_unittest(
   strcat_test
   SUITE

diff  --git a/libc/test/src/string/stpcpy_test.cpp b/libc/test/src/string/stpcpy_test.cpp
new file mode 100644
index 000000000000..90ec5311b9b9
--- /dev/null
+++ b/libc/test/src/string/stpcpy_test.cpp
@@ -0,0 +1,45 @@
+//===-- Unittests for stpcpy ----------------------------------------------===//
+//
+// 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/stpcpy.h"
+#include "utils/UnitTest/Test.h"
+
+#include "src/string/string_utils.h"
+
+TEST(LlvmLibcStpCpyTest, EmptySrc) {
+  const char *empty = "";
+  size_t srcSize = __llvm_libc::internal::string_length(empty);
+  char dest[4] = {'a', 'b', 'c', '\0'};
+
+  char *result = __llvm_libc::stpcpy(dest, empty);
+  ASSERT_EQ(dest + srcSize, result);
+  ASSERT_EQ(result[0], '\0');
+  ASSERT_STREQ(dest, empty);
+}
+
+TEST(LlvmLibcStpCpyTest, EmptyDest) {
+  const char *abc = "abc";
+  size_t srcSize = __llvm_libc::internal::string_length(abc);
+  char dest[4];
+
+  char *result = __llvm_libc::stpcpy(dest, abc);
+  ASSERT_EQ(dest + srcSize, result);
+  ASSERT_EQ(result[0], '\0');
+  ASSERT_STREQ(dest, abc);
+}
+
+TEST(LlvmLibcStpCpyTest, OffsetDest) {
+  const char *abc = "abc";
+  size_t srcSize = __llvm_libc::internal::string_length(abc);
+  char dest[7] = {'x', 'y', 'z'};
+
+  char *result = __llvm_libc::stpcpy(dest + 3, abc);
+  ASSERT_EQ(dest + 3 + srcSize, result);
+  ASSERT_EQ(result[0], '\0');
+  ASSERT_STREQ(dest, "xyzabc");
+}

diff  --git a/libc/test/src/string/stpncpy_test.cpp b/libc/test/src/string/stpncpy_test.cpp
new file mode 100644
index 000000000000..855be58941ce
--- /dev/null
+++ b/libc/test/src/string/stpncpy_test.cpp
@@ -0,0 +1,73 @@
+//===-- Unittests for stpncpy ---------------------------------------------===//
+//
+// 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/__support/CPP/ArrayRef.h"
+#include "src/string/stpncpy.h"
+#include "utils/UnitTest/Test.h"
+#include <stddef.h> // For size_t.
+
+class LlvmLibcStpncpyTest : public __llvm_libc::testing::Test {
+public:
+  void check_stpncpy(__llvm_libc::cpp::MutableArrayRef<char> dst,
+                     const __llvm_libc::cpp::ArrayRef<char> src, size_t n,
+                     const __llvm_libc::cpp::ArrayRef<char> expected,
+                     size_t expectedCopied) {
+    // Making sure we don't overflow buffer.
+    ASSERT_GE(dst.size(), n);
+    // Making sure stpncpy returns a pointer to the end of dst.
+    ASSERT_EQ(__llvm_libc::stpncpy(dst.data(), src.data(), n),
+              dst.data() + expectedCopied);
+    // Expected must be of the same size as dst.
+    ASSERT_EQ(dst.size(), expected.size());
+    // Expected and dst are the same.
+    for (size_t i = 0; i < expected.size(); ++i)
+      ASSERT_EQ(expected[i], dst[i]);
+  }
+};
+
+TEST_F(LlvmLibcStpncpyTest, Untouched) {
+  char dst[] = {'a', 'b'};
+  const char src[] = {'x', '\0'};
+  const char expected[] = {'a', 'b'};
+  check_stpncpy(dst, src, 0, expected, 0);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyOne) {
+  char dst[] = {'a', 'b'};
+  const char src[] = {'x', 'y'};
+  const char expected[] = {'x', 'b'}; // no \0 is appended
+  check_stpncpy(dst, src, 1, expected, 1);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyNull) {
+  char dst[] = {'a', 'b'};
+  const char src[] = {'\0', 'y'};
+  const char expected[] = {'\0', 'b'};
+  check_stpncpy(dst, src, 1, expected, 0);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyPastSrc) {
+  char dst[] = {'a', 'b'};
+  const char src[] = {'\0', 'y'};
+  const char expected[] = {'\0', '\0'};
+  check_stpncpy(dst, src, 2, expected, 0);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyTwoNoNull) {
+  char dst[] = {'a', 'b'};
+  const char src[] = {'x', 'y'};
+  const char expected[] = {'x', 'y'};
+  check_stpncpy(dst, src, 2, expected, 2);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyTwoWithNull) {
+  char dst[] = {'a', 'b'};
+  const char src[] = {'x', '\0'};
+  const char expected[] = {'x', '\0'};
+  check_stpncpy(dst, src, 2, expected, 1);
+}

diff  --git a/libc/test/src/string/strcpy_test.cpp b/libc/test/src/string/strcpy_test.cpp
index 14fa86c994d9..1b6c47741b17 100644
--- a/libc/test/src/string/strcpy_test.cpp
+++ b/libc/test/src/string/strcpy_test.cpp
@@ -9,6 +9,16 @@
 #include "src/string/strcpy.h"
 #include "utils/UnitTest/Test.h"
 
+TEST(LlvmLibcStrCpyTest, EmptySrc) {
+  const char *empty = "";
+  char dest[4] = {'a', 'b', 'c', '\0'};
+
+  char *result = __llvm_libc::strcpy(dest, empty);
+  ASSERT_EQ(dest, result);
+  ASSERT_STREQ(dest, result);
+  ASSERT_STREQ(dest, empty);
+}
+
 TEST(LlvmLibcStrCpyTest, EmptyDest) {
   const char *abc = "abc";
   char dest[4];


        


More information about the libc-commits mailing list