[libc] Annex K: strcpy_s#197709
Open
vhscampos wants to merge 1 commit into
Open
Conversation
This patch adds Annex K's `strcpy_s`.
|
@llvm/pr-subscribers-libc Author: Victor Campos (vhscampos) ChangesThis patch adds Annex K's Full diff: https://github.com/llvm/llvm-project/pull/197709.diff 11 Files Affected:
diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index 452abd985b3a5..110538f8b6be5 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -75,6 +75,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strcmp
libc.src.string.strcoll
libc.src.string.strcpy
+ libc.src.string.strcpy_s
libc.src.string.strcspn
libc.src.string.strdup
libc.src.string.strerror
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 41c80efc64227..69d13fa293e6e 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -75,6 +75,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strcmp
libc.src.string.strcoll
libc.src.string.strcpy
+ libc.src.string.strcpy_s
libc.src.string.strcspn
libc.src.string.strdup
libc.src.string.strerror
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b7c9cabd934b4..30c3034fa7f28 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -68,6 +68,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strcmp
libc.src.string.strcoll
libc.src.string.strcpy
+ libc.src.string.strcpy_s
libc.src.string.strcspn
libc.src.string.strdup
libc.src.string.strerror
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 906f36d45e337..f006c5476a6e0 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -41,6 +41,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strchrnul
libc.src.string.strcmp
libc.src.string.strcpy
+ libc.src.string.strcpy_s
libc.src.string.strcspn
libc.src.string.strlcat
libc.src.string.strlcpy
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 9970f079abc08..dab5062d18d0c 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -70,6 +70,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strcmp
libc.src.string.strcoll
libc.src.string.strcpy
+ libc.src.string.strcpy_s
libc.src.string.strcspn
libc.src.string.strdup
libc.src.string.strerror
diff --git a/libc/include/string.yaml b/libc/include/string.yaml
index c0a96e58dbc94..234cc6e77cfd4 100644
--- a/libc/include/string.yaml
+++ b/libc/include/string.yaml
@@ -169,6 +169,15 @@ functions:
arguments:
- type: char *__restrict
- type: const char *__restrict
+ - name: strcpy_s
+ standards:
+ - stdc
+ return_type: errno_t
+ arguments:
+ - type: char *__restrict
+ - type: rsize_t
+ - type: const char *__restrict
+ guard: LIBC_HAS_ANNEX_K
- name: strcspn
standards:
- stdc
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index e28fe7af8cf25..accf30e865ad9 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -172,6 +172,25 @@ add_entrypoint_object(
.string_utils
)
+add_entrypoint_object(
+ strcpy_s
+ SRCS
+ strcpy_s.cpp
+ HDRS
+ strcpy_s.h
+ DEPENDS
+ .memory_utils.inline_memcpy
+ .string_utils
+ .strnlen_s
+ libc.src.__support.common
+ libc.src.__support.constraint_handler
+ libc.src.__support.macros.config
+ libc.hdr.types.constraint_handler_t
+ libc.hdr.types.errno_t
+ libc.hdr.types.rsize_t
+ libc.hdr.stdint_proxy
+)
+
add_entrypoint_object(
strcspn
SRCS
diff --git a/libc/src/string/strcpy_s.cpp b/libc/src/string/strcpy_s.cpp
new file mode 100644
index 0000000000000..7553d2284d906
--- /dev/null
+++ b/libc/src/string/strcpy_s.cpp
@@ -0,0 +1,71 @@
+//===-- Implementation of strcpy_s ----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// For RSIZE_MAX
+#define __STDC_WANT_LIB_EXT1__ 1
+#include "hdr/stdint_proxy.h"
+#undef __STDC_WANT_LIB_EXT1__
+
+#include "hdr/types/constraint_handler_t.h"
+#include "hdr/types/errno_t.h"
+#include "hdr/types/rsize_t.h"
+#include "src/__support/common.h"
+#include "src/__support/constraint_handler.h"
+#include "src/__support/macros/config.h"
+#include "src/string/memory_utils/inline_memcpy.h"
+#include "src/string/strcpy_s.h"
+#include "src/string/string_utils.h"
+#include "src/string/strnlen_s.h"
+
+#define ERRNO_T_FAIL 1
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(errno_t, strcpy_s,
+ (char *__restrict s1, rsize_t s1max,
+ const char *__restrict s2)) {
+ const char *constraint_violation_msg = 0;
+ size_t count;
+
+ if (s1 == 0) {
+ constraint_violation_msg = "strcpy_s: s1 is null";
+ } else if (s2 == 0) {
+ constraint_violation_msg = "strcpy_s: s2 is null";
+ } else if (s1max > RSIZE_MAX) {
+ constraint_violation_msg = "strcpy_s: s1max exceeds RSIZE_MAX";
+ } else if (s1max == 0) {
+ constraint_violation_msg = "strcpy_s: s1max is 0";
+ } else if (count = strnlen_s(s2, s1max);
+ s1max == count) { // count can't be greater than s1max by
+ // definition, so no need to check for this case
+ constraint_violation_msg = "strcpy_s: s1max is too small for s2";
+ }
+ // Check overlap using the full regions defined by the standard, including the
+ // terminating null byte:
+ // destination: [s1, s1 + s1max)
+ // source: [s2, s2 + count + 1)
+ // Use s1max for the destination's length, not count + 1, because the
+ // standard allows for overwriting the entire destination region, even if
+ // s2's length is smaller than s1max.
+ else if (s2 < (s1 + s1max) && s1 < (s2 + count + 1)) {
+ constraint_violation_msg = "strcpy_s: s1 and s2 overlap";
+ }
+
+ if (constraint_violation_msg) {
+ if (s1 != 0 && s1max > 0 && s1max <= RSIZE_MAX) {
+ s1[0] = '\0';
+ }
+ libc_global_constraint_handler(constraint_violation_msg, 0, ERRNO_T_FAIL);
+ return ERRNO_T_FAIL;
+ }
+
+ inline_memcpy(s1, s2, count + 1);
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/string/strcpy_s.h b/libc/src/string/strcpy_s.h
new file mode 100644
index 0000000000000..7a38f8dbbf890
--- /dev/null
+++ b/libc/src/string/strcpy_s.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strcpy_s ----------------------*- 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_STRCPY_S_H
+#define LLVM_LIBC_SRC_STRING_STRCPY_S_H
+
+#include "hdr/types/errno_t.h"
+#include "hdr/types/rsize_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+errno_t strcpy_s(char *__restrict s1, rsize_t s1max, const char *__restrict s2);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STRING_STRCPY_S_H
diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt
index 17927ea93ed1e..e79d8e6257f5d 100644
--- a/libc/test/src/string/CMakeLists.txt
+++ b/libc/test/src/string/CMakeLists.txt
@@ -149,6 +149,19 @@ add_libc_test(
libc.src.string.strcpy
)
+add_libc_test(
+ strcpy_s_test
+ SUITE
+ libc-string-tests
+ SRCS
+ strcpy_s_test.cpp
+ DEPENDS
+ libc.src.string.strcpy_s
+ libc.hdr.stdint_proxy
+ libc.hdr.types.errno_t
+ libc.test.UnitTest.ConstraintHandlerCheckingTest
+)
+
add_libc_test(
strcspn_test
SUITE
diff --git a/libc/test/src/string/strcpy_s_test.cpp b/libc/test/src/string/strcpy_s_test.cpp
new file mode 100644
index 0000000000000..40625337b001f
--- /dev/null
+++ b/libc/test/src/string/strcpy_s_test.cpp
@@ -0,0 +1,122 @@
+//===-- Unittests for strcpy_s --------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#define __STDC_WANT_LIB_EXT1__ 1
+#include "hdr/stdint_proxy.h"
+#undef __STDC_WANT_LIB_EXT1__
+
+#include "hdr/types/errno_t.h"
+#include "src/string/strcpy_s.h"
+#include "test/UnitTest/ConstraintHandlerCheckingTest.h"
+
+using LlvmLibcStrCpySTest =
+ LIBC_NAMESPACE::testing::ConstraintHandlerCheckingTest;
+
+// Success cases
+TEST_F(LlvmLibcStrCpySTest, SuccessfulCopy) {
+ char s1[8];
+ const char *s2 = "abc";
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s1, sizeof(s1), s2);
+ ASSERT_EQ(result, 0);
+ ASSERT_STREQ(s1, s2);
+ ASSERT_STREQ(buffer, "");
+}
+
+TEST_F(LlvmLibcStrCpySTest, ExactFitSuccessfulCopy) {
+ char s1[4];
+ const char *s2 = "abc";
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s1, sizeof(s1), s2);
+ ASSERT_EQ(result, 0);
+ ASSERT_STREQ(s1, s2);
+ ASSERT_STREQ(buffer, "");
+}
+
+TEST_F(LlvmLibcStrCpySTest, AdjacentObjectsDoNotOverlap) {
+ char s[8] = {'a', 'b', 'c', '\0', '?', '?', '?', '?'};
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s + 4, 4, s);
+ ASSERT_EQ(result, 0);
+ ASSERT_STREQ(s + 4, "abc");
+ ASSERT_STREQ(buffer, "");
+}
+
+TEST_F(LlvmLibcStrCpySTest, EmptySourceString) {
+ char s1[4];
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s1, sizeof(s1), "");
+ ASSERT_EQ(result, 0);
+ ASSERT_EQ(s1[0], '\0');
+ ASSERT_STREQ(buffer, "");
+}
+
+// Failure cases
+TEST_F(LlvmLibcStrCpySTest, NullS1) {
+ const char *s2 = "abc";
+ char *s1 = 0;
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s1, 4, s2);
+ ASSERT_NE(result, 0);
+ ASSERT_STREQ(buffer, "strcpy_s: s1 is null");
+}
+
+TEST_F(LlvmLibcStrCpySTest, NullS2) {
+ char s1[4];
+ const char *s2 = 0;
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s1, 4, s2);
+ ASSERT_NE(result, 0);
+ ASSERT_EQ(s1[0], '\0');
+ ASSERT_STREQ(buffer, "strcpy_s: s2 is null");
+}
+
+TEST_F(LlvmLibcStrCpySTest, S1MaxGreaterThanRSizeMax) {
+ char s1[4];
+ const char *s2 = "abc";
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s1, RSIZE_MAX + 1, s2);
+ ASSERT_NE(result, 0);
+ ASSERT_STREQ(buffer, "strcpy_s: s1max exceeds RSIZE_MAX");
+}
+
+TEST_F(LlvmLibcStrCpySTest, S1MaxIsZero) {
+ char s1[4];
+ const char *s2 = "abc";
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s1, 0, s2);
+ ASSERT_NE(result, 0);
+ ASSERT_STREQ(buffer, "strcpy_s: s1max is 0");
+}
+
+TEST_F(LlvmLibcStrCpySTest, S1MaxTooSmallForS2) {
+ char s1[3];
+ const char *s2 = "abc";
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s1, 3, s2);
+ ASSERT_NE(result, 0);
+ ASSERT_EQ(s1[0], '\0');
+ ASSERT_STREQ(buffer, "strcpy_s: s1max is too small for s2");
+
+ s2 = "abcd";
+ s1[0] = '?';
+ buffer[0] = '\0';
+ result = LIBC_NAMESPACE::strcpy_s(s1, 3, s2);
+ ASSERT_NE(result, 0);
+ ASSERT_EQ(s1[0], '\0');
+ ASSERT_STREQ(buffer, "strcpy_s: s1max is too small for s2");
+}
+
+TEST_F(LlvmLibcStrCpySTest, OverlappingObjects) {
+ char s[10] = "123456789";
+
+ errno_t result = LIBC_NAMESPACE::strcpy_s(s, 6, s + 4);
+ ASSERT_NE(result, 0);
+ ASSERT_EQ(s[0], '\0');
+ ASSERT_STREQ(buffer, "strcpy_s: s1 and s2 overlap");
+}
|
🐧 Linux x64 Test ResultsThe build failed before running any tests. Click on a failure below to see the details. runtimes/runtimes-stamps/runtimes-configure /home/gha/actions-runner/_work/llvm-project/llvm-project/build/runtimes/runtimes-stamps/runtimes-configureIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This patch adds Annex K's
strcpy_s.