[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
This commit is contained in:
Michael Jones 2021-10-15 15:11:37 -07:00
parent a320f877ce
commit 9b6f8b985c
11 changed files with 280 additions and 0 deletions

View File

@ -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

View File

@ -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>,

View File

@ -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

View File

@ -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

18
libc/src/string/stpcpy.h Normal file
View File

@ -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

View File

@ -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

20
libc/src/string/stpncpy.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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");
}

View File

@ -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);
}

View File

@ -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];