Adjust the implementation of strncpy_s() for Linux

This change:
- prevents writing memory out of the range of the destination buffer
- prevents calling strlen() with non-null terminated c-string
- corrects the logic, which validates passed range to proceed
when real length fits the destination buffer

Related-To: NEO-7264
Signed-off-by: Wrobel, Patryk <patryk.wrobel@intel.com>
This commit is contained in:
Wrobel, Patryk
2022-08-17 15:46:39 +00:00
committed by Compute-Runtime-Automation
parent 5bdf758049
commit dda5b19859
8 changed files with 88 additions and 71 deletions

View File

@@ -31,28 +31,6 @@ inline int strcpy_s(char *dst, size_t dstSize, const char *src) { // NOLINT(read
return 0;
}
inline int strncpy_s(char *dst, size_t numberOfElements, const char *src, size_t count) { // NOLINT(readability-identifier-naming)
if ((dst == nullptr) || (src == nullptr)) {
return -EINVAL;
}
if (numberOfElements < count) {
return -ERANGE;
}
size_t length = strlen(src);
if (length > count) {
length = count;
}
memcpy(dst, src, length);
if (length < numberOfElements) {
numberOfElements = length;
}
dst[numberOfElements] = '\0';
return 0;
}
inline size_t strnlen_s(const char *str, size_t count) { // NOLINT(readability-identifier-naming)
if (str == nullptr) {
return 0;
@@ -66,6 +44,22 @@ inline size_t strnlen_s(const char *str, size_t count) { // NOLINT(readability-i
return count;
}
inline int strncpy_s(char *dst, size_t numberOfElements, const char *src, size_t count) { // NOLINT(readability-identifier-naming)
if ((dst == nullptr) || (src == nullptr)) {
return -EINVAL;
}
size_t length = strnlen_s(src, count);
if (numberOfElements <= count && numberOfElements <= length) {
return -ERANGE;
}
memcpy(dst, src, length);
dst[length] = '\0';
return 0;
}
inline int memcpy_s(void *dst, size_t destSize, const void *src, size_t count) { // NOLINT(readability-identifier-naming)
if ((dst == nullptr) || (src == nullptr)) {
return -EINVAL;

View File

@@ -27,7 +27,7 @@ TEST(StringHelpers, GivenParamsWhenUsingStrncpyThenReturnIsCorrect) {
ret = strncpy_s(dst, 1024, nullptr, 1024);
EXPECT_EQ(ret, -EINVAL);
ret = strncpy_s(dst, 512, src, 1024);
ret = strncpy_s(dst, 10, src, 1024);
EXPECT_EQ(ret, -ERANGE);
memset(dst, 0, sizeof(dst));
@@ -37,19 +37,41 @@ TEST(StringHelpers, GivenParamsWhenUsingStrncpyThenReturnIsCorrect) {
for (size_t i = strlen(src) / 2; i < sizeof(dst); i++)
EXPECT_EQ(0, dst[i]);
memset(dst, 0, sizeof(dst));
ret = strncpy_s(dst, strlen(src) / 2, src, strlen(src) / 2);
EXPECT_EQ(ret, 0);
EXPECT_EQ(0, memcmp(dst, src, strlen(src) / 2));
for (size_t i = strlen(src) / 2; i < sizeof(dst); i++)
EXPECT_EQ(0, dst[i]);
ret = strncpy_s(dst, 1024, src, 1024);
ASSERT_EQ(0, ret);
strncpy_s(dst, 1024, src, 1024);
EXPECT_EQ(0, memcmp(dst, src, strlen(src)));
for (size_t i = strlen(src); i < sizeof(dst); i++)
EXPECT_EQ(0, dst[i]);
}
TEST(StringHelpers, GivenCountGreaterEqualToNumberOfElementsThenReturnErangeAndSetFirstStringToNullTerminator) {
// strncpy_s() copies at most COUNT bytes and appends null-terminator at dst[COUNT].
// It means, that for given COUNT, at least COUNT+1 bytes are required in dst buffer.
const size_t firstWordLength = 9;
char src[] = "c-strings are serious business!";
char dst[firstWordLength] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'};
const auto ret = strncpy_s(dst, sizeof(dst), src, firstWordLength);
EXPECT_EQ(-ERANGE, ret);
}
TEST(StringHelpers, GivenNotNullTerminatedSourceThenCopyAtMostCountBytesAndAppendNulltermination) {
// If null-terminator is missing, then strncpy_s() copies COUNT bytes and stores it at dst[COUNT].
const size_t srcLength = 8;
char src[srcLength] = {'c', '-', 's', 't', 'r', 'i', 'n', 'g'};
const size_t nullterminatorLength = 1;
char dst[srcLength + nullterminatorLength] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'};
const auto ret = strncpy_s(dst, sizeof(dst), src, srcLength);
ASSERT_EQ(0, ret);
EXPECT_STREQ("c-string", dst);
}
TEST(StringHelpers, GivenParamsWhenUsingMemmoveThenReturnIsCorrect) {
char dst[1024] = "";
char src[1024] = "HelloWorld";