Skip to content

Commit 6f08d75

Browse files
author
Sriya Pratipati
committed
[libc] mbsrtowcs implementation
Implemented mbsrtowcs and tests for the function.
1 parent 5996aad commit 6f08d75

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

libc/src/__support/wchar/mbsrtowcs.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ ErrorOr<size_t> mbsrtowcs(wchar_t *__restrict dst, const char **__restrict src,
2525
// Converting characters until we reach error or null terminator
2626
for (; i < len; ++i, ++dst) {
2727
auto check = mbrtowc(dst, *src, 4, ps);
28-
// Encoding error
28+
// Encoding error/invalid mbstate
2929
if (!check.has_value())
30-
return Error(-1);
30+
return Error(check.error());
3131
// Successfully encoded, check for null terminator
3232
if (*dst == L'\0') {
3333
*src = nullptr;

libc/src/wchar/mbsrtowcs.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ LLVM_LIBC_FUNCTION(size_t, mbsrtowcs,
3232
: reinterpret_cast<internal::mbstate *>(ps));
3333
if (!ret.has_value()) {
3434
// Encoding failure
35-
libc_errno = EILSEQ;
35+
libc_errno = ret.error();
3636
return -1;
3737
}
3838
return ret.value();

libc/test/src/wchar/mbsrtowcs_test.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "hdr/types/wchar_t.h"
1010
#include "src/__support/libc_errno.h"
11+
#include "src/__support/wchar/mbstate.h"
1112
#include "src/string/memset.h"
1213
#include "src/wchar/mbsrtowcs.h"
1314
#include "test/UnitTest/ErrnoCheckingTest.h"
@@ -21,6 +22,7 @@ TEST_F(LlvmLibcMBSRToWCSTest, OneByteOneCharacter) {
2122
const char *ch = "A";
2223
wchar_t dest[2];
2324
size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &ch, 2, mb);
25+
ASSERT_ERRNO_SUCCESS();
2426
ASSERT_TRUE(dest[0] == L'A');
2527
ASSERT_TRUE(dest[1] == L'\0');
2628
// Should not count null terminator in number
@@ -33,6 +35,7 @@ TEST_F(LlvmLibcMBSRToWCSTest, MultiByteOneCharacter) {
3335
const char *src = "\xf0\x9f\x98\xb9"; // laughing cat emoji 😹
3436
wchar_t dest[2];
3537
size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 2, nullptr);
38+
ASSERT_ERRNO_SUCCESS();
3639
ASSERT_EQ(static_cast<int>(dest[0]), 128569);
3740
ASSERT_TRUE(dest[1] == L'\0');
3841
// Should not count null terminator in number
@@ -46,6 +49,7 @@ TEST_F(LlvmLibcMBSRToWCSTest, MultiByteTwoCharacters) {
4649
const char *src = "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9";
4750
wchar_t dest[3];
4851
size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 3, nullptr);
52+
ASSERT_ERRNO_SUCCESS();
4953
ASSERT_EQ(static_cast<int>(dest[0]), 128569);
5054
ASSERT_EQ(static_cast<int>(dest[1]), 128569);
5155
ASSERT_TRUE(dest[2] == L'\0');
@@ -62,6 +66,7 @@ TEST_F(LlvmLibcMBSRToWCSTest, ReadLessThanStringLength) {
6266
const char *check = src;
6367
wchar_t dest[3];
6468
size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 3, nullptr);
69+
ASSERT_ERRNO_SUCCESS();
6570
// Should have read 3 emojis
6671
ASSERT_EQ(static_cast<int>(n), 3);
6772
ASSERT_EQ(static_cast<int>(dest[0]), 128569);
@@ -98,10 +103,26 @@ TEST_F(LlvmLibcMBSRToWCSTest, NullDestination) {
98103
const char *src =
99104
"\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9";
100105
size_t n = LIBC_NAMESPACE::mbsrtowcs(nullptr, &src, 5, nullptr);
106+
ASSERT_ERRNO_SUCCESS();
101107
// Null destination should still return correct number of read chars
102108
ASSERT_EQ(static_cast<int>(n), 4);
103109
}
104110

111+
TEST_F(LlvmLibcMBSRToWCSTest, InvalidMBState) {
112+
mbstate_t *mb;
113+
LIBC_NAMESPACE::internal::mbstate inv;
114+
inv.total_bytes = 6;
115+
mb = reinterpret_cast<mbstate_t *>(&inv);
116+
// Four laughing cat emojis "😹😹😹😹"
117+
const char *src =
118+
"\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9";
119+
wchar_t dest[3];
120+
size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 3, mb);
121+
// Should fail from invalid mbstate
122+
ASSERT_EQ(static_cast<int>(n), -1);
123+
ASSERT_ERRNO_EQ(EINVAL);
124+
}
125+
105126
#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)
106127
TEST_F(LlvmLibcMBSRToWCSTest, NullSource) {
107128
// Passing in a nullptr source should crash the program

0 commit comments

Comments
 (0)