[libc-commits] [libc] 9e9803b - [libc] Add strncat and fix strcat

Michael Jones via libc-commits libc-commits at lists.llvm.org
Tue Oct 12 11:18:22 PDT 2021


Author: Michael Jones
Date: 2021-10-12T18:18:18Z
New Revision: 9e9803bf82500b8a075d9658d2b4c248115f4a6f

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

LOG: [libc] Add strncat and fix strcat

This adds strncat to llvm libc. In addition, an error was found with
strcat and that was fixed.

Reviewed By: lntue

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

Added: 
    libc/src/string/strncat.cpp
    libc/src/string/strncat.h
    libc/test/src/string/strncat_test.cpp

Modified: 
    libc/config/linux/x86_64/entrypoints.txt
    libc/src/string/CMakeLists.txt
    libc/src/string/strcat.cpp
    libc/test/src/string/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index b261a1a1d7614..56ae31d1550fb 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -35,6 +35,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strcpy
     libc.src.string.strcspn
     libc.src.string.strlen
+    libc.src.string.strncat
     libc.src.string.strncmp
     libc.src.string.strncpy
     libc.src.string.strnlen

diff  --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index aa22fa08e9f4c..e5d6ebc2c1054 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -95,6 +95,17 @@ add_entrypoint_object(
     libc.include.string
 )
 
+add_entrypoint_object(
+  strncat
+  SRCS
+    strncat.cpp
+  HDRS
+    strncat.h
+  DEPENDS
+    .strncpy
+    .string_utils
+)
+
 add_entrypoint_object(
   strncmp
   SRCS

diff  --git a/libc/src/string/strcat.cpp b/libc/src/string/strcat.cpp
index 176a42a2c7515..fef2758f04ced 100644
--- a/libc/src/string/strcat.cpp
+++ b/libc/src/string/strcat.cpp
@@ -16,7 +16,10 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(char *, strcat,
                    (char *__restrict dest, const char *__restrict src)) {
-  __llvm_libc::strcpy(dest + internal::string_length(dest), src);
+  size_t destLength = internal::string_length(dest);
+  size_t srcLength = internal::string_length(src);
+  __llvm_libc::strcpy(dest + destLength, src);
+  dest[destLength + srcLength] = '\0';
   return dest;
 }
 

diff  --git a/libc/src/string/strncat.cpp b/libc/src/string/strncat.cpp
new file mode 100644
index 0000000000000..968c1e2703bd8
--- /dev/null
+++ b/libc/src/string/strncat.cpp
@@ -0,0 +1,28 @@
+//===-- Implementation of strncat -----------------------------------------===//
+//
+// 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/strncat.h"
+#include "src/string/string_utils.h"
+#include "src/string/strncpy.h"
+
+#include "src/__support/common.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(char *, strncat,
+                   (char *__restrict dest, const char *__restrict src,
+                    size_t count)) {
+  size_t srcLength = internal::string_length(src);
+  size_t copyAmount = srcLength > count ? count : srcLength;
+  size_t destLength = internal::string_length(dest);
+  __llvm_libc::strncpy(dest + destLength, src, copyAmount);
+  dest[destLength + copyAmount] = '\0';
+  return dest;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/string/strncat.h b/libc/src/string/strncat.h
new file mode 100644
index 0000000000000..9b2c70fca5788
--- /dev/null
+++ b/libc/src/string/strncat.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for strncat -----------------------*- 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_STRNCAT_H
+#define LLVM_LIBC_SRC_STRING_STRNCAT_H
+
+#include <string.h>
+
+namespace __llvm_libc {
+
+char *strncat(char *__restrict dest, const char *__restrict src, size_t count);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STRNCAT_H

diff  --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt
index d68c1c9b56644..2d6d9199b5e16 100644
--- a/libc/test/src/string/CMakeLists.txt
+++ b/libc/test/src/string/CMakeLists.txt
@@ -82,6 +82,16 @@ add_libc_unittest(
     libc.src.string.strlen
 )
 
+add_libc_unittest(
+  strncat_test
+  SUITE
+    libc_string_unittests
+  SRCS
+    strncat_test.cpp
+  DEPENDS
+    libc.src.string.strncat
+)
+
 add_libc_unittest(
   strncmp_test
   SUITE

diff  --git a/libc/test/src/string/strncat_test.cpp b/libc/test/src/string/strncat_test.cpp
new file mode 100644
index 0000000000000..f7442dc95c8ce
--- /dev/null
+++ b/libc/test/src/string/strncat_test.cpp
@@ -0,0 +1,76 @@
+//===-- Unittests for strncat ---------------------------------------------===//
+//
+// 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/strncat.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(LlvmLibcStrNCatTest, EmptyDest) {
+  const char *abc = "abc";
+  char dest[4];
+
+  dest[0] = '\0';
+
+  // Start by copying nothing
+  char *result = __llvm_libc::strncat(dest, abc, 0);
+  ASSERT_EQ(dest, result);
+  ASSERT_EQ(dest[0], '\0');
+
+  // Then copy part of it.
+  result = __llvm_libc::strncat(dest, abc, 1);
+  ASSERT_EQ(dest, result);
+  ASSERT_STREQ(dest, "a");
+
+  // Reset for the last test.
+  dest[0] = '\0';
+
+  // Then copy all of it.
+  result = __llvm_libc::strncat(dest, abc, 3);
+  ASSERT_EQ(dest, result);
+  ASSERT_STREQ(dest, result);
+  ASSERT_STREQ(dest, abc);
+}
+
+TEST(LlvmLibcStrNCatTest, NonEmptyDest) {
+  const char *abc = "abc";
+  char dest[7];
+
+  dest[0] = 'x';
+  dest[1] = 'y';
+  dest[2] = 'z';
+  dest[3] = '\0';
+
+  // Copy only part of the string onto the end
+  char *result = __llvm_libc::strncat(dest, abc, 1);
+  ASSERT_EQ(dest, result);
+  ASSERT_STREQ(dest, "xyza");
+
+  // Copy a bit more, but without resetting.
+  result = __llvm_libc::strncat(dest, abc, 2);
+  ASSERT_EQ(dest, result);
+  ASSERT_STREQ(dest, "xyzaab");
+
+  // Set just the end marker, to make sure it overwrites properly.
+  dest[3] = '\0';
+
+  result = __llvm_libc::strncat(dest, abc, 3);
+  ASSERT_EQ(dest, result);
+  ASSERT_STREQ(dest, "xyzabc");
+
+  // Check that copying still works when count > src length
+  dest[0] = '\0';
+  // And that it doesn't write beyond what is necessary.
+  dest[4] = 'Z';
+  result = __llvm_libc::strncat(dest, abc, 4);
+  ASSERT_EQ(dest, result);
+  ASSERT_STREQ(dest, "abc");
+  ASSERT_EQ(dest[4], 'Z');
+
+  result = __llvm_libc::strncat(dest, abc, 5);
+  ASSERT_EQ(dest, result);
+  ASSERT_STREQ(dest, "abcabc");
+}


        


More information about the libc-commits mailing list