[libc-commits] [libc] a85dcb8 - [libc] fix oob and overflow bugs in wcslcat and wcsncat (#203697)
via libc-commits
libc-commits at lists.llvm.org
Thu Jun 25 03:55:08 PDT 2026
Author: Hardik Kumar
Date: 2026-06-25T11:55:03+01:00
New Revision: a85dcb8f907416e650d992c0ba52909e64c20611
URL: https://github.com/llvm/llvm-project/commit/a85dcb8f907416e650d992c0ba52909e64c20611
DIFF: https://github.com/llvm/llvm-project/commit/a85dcb8f907416e650d992c0ba52909e64c20611.diff
LOG: [libc] fix oob and overflow bugs in wcslcat and wcsncat (#203697)
closes #203649
- I have added a check in `libc/src/wchar/wcslcat.cpp` to prevent
overflow caused by when static_cast wraps the limit.
- For the `wcsncat` implementation I have fixed the condition in the for
loop to first check if `i` is within bounds preventing OOB access on
`s2`
I am new to the codebase so any feedback would be very helpful and I
will be happy to follow up promptly after a review!
Added:
Modified:
libc/src/wchar/wcslcat.cpp
libc/src/wchar/wcsncat.cpp
libc/test/src/wchar/wcslcat_test.cpp
libc/test/src/wchar/wcsncat_test.cpp
Removed:
################################################################################
diff --git a/libc/src/wchar/wcslcat.cpp b/libc/src/wchar/wcslcat.cpp
index eb318e066f7a0..456aac4543e41 100644
--- a/libc/src/wchar/wcslcat.cpp
+++ b/libc/src/wchar/wcslcat.cpp
@@ -21,8 +21,10 @@ LLVM_LIBC_FUNCTION(size_t, wcslcat,
size_t dstsize)) {
const size_t dstlen = internal::string_length(dst);
const size_t srclen = internal::string_length(src);
+ if (dstlen >= dstsize)
+ return dstsize + srclen;
int limit = static_cast<int>(dstsize - dstlen - 1);
- size_t returnval = (dstsize < dstlen ? dstsize : dstlen) + srclen;
+ size_t returnval = dstlen + srclen;
if (limit < 0)
return returnval;
int i = 0;
diff --git a/libc/src/wchar/wcsncat.cpp b/libc/src/wchar/wcsncat.cpp
index 62595b4b5418c..985fb5f1cbace 100644
--- a/libc/src/wchar/wcsncat.cpp
+++ b/libc/src/wchar/wcsncat.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(wchar_t *, wcsncat,
size_t n)) {
size_t size = internal::string_length(s1);
size_t i = 0;
- for (; s2[i] && i < n; ++i)
+ for (; i < n && s2[i]; ++i)
s1[size + i] = s2[i];
// Appending null character to the end of the result.
s1[size + i] = L'\0';
diff --git a/libc/test/src/wchar/wcslcat_test.cpp b/libc/test/src/wchar/wcslcat_test.cpp
index bad37496384e2..564a5c60006e6 100644
--- a/libc/test/src/wchar/wcslcat_test.cpp
+++ b/libc/test/src/wchar/wcslcat_test.cpp
@@ -55,3 +55,15 @@ TEST(LlvmLibcWCSLCatTest, SmallerNoOverwriteAfter0) {
ASSERT_TRUE(dst[7] == L'\0');
ASSERT_EQ(res, size_t(4));
}
+
+TEST(LlvmLibcWCSLCatTest, DstsizeLessThanDstlen) {
+ const wchar_t *src = L"d";
+ wchar_t dst[4]{L"abc"};
+ // Should return src length + dst size
+ size_t res = LIBC_NAMESPACE::wcslcat(dst, src, 2);
+ ASSERT_TRUE(dst[0] == L'a');
+ ASSERT_TRUE(dst[1] == L'b');
+ ASSERT_TRUE(dst[2] == L'c');
+ ASSERT_TRUE(dst[3] == L'\0');
+ ASSERT_EQ(res, size_t(3));
+}
diff --git a/libc/test/src/wchar/wcsncat_test.cpp b/libc/test/src/wchar/wcsncat_test.cpp
index 47359f88cec9e..0795685713e00 100644
--- a/libc/test/src/wchar/wcsncat_test.cpp
+++ b/libc/test/src/wchar/wcsncat_test.cpp
@@ -80,3 +80,15 @@ TEST(LlvmLibcWCSNCatTest, NonEmptyDest) {
ASSERT_TRUE(dest[3] == L'\0');
ASSERT_TRUE(dest[4] == L'Z');
}
+
+TEST(LlvmLibcWCSNCatTest, OOBAccess) {
+ wchar_t dest[4] = {L'\0'};
+ wchar_t src[3] = {L'a', L'b', L'c'};
+
+ // Checking the bound
+ LIBC_NAMESPACE::wcsncat(dest, src, 3);
+ ASSERT_TRUE(dest[0] == L'a');
+ ASSERT_TRUE(dest[1] == L'b');
+ ASSERT_TRUE(dest[2] == L'c');
+ ASSERT_TRUE(dest[3] == L'\0');
+}
More information about the libc-commits
mailing list