Skip to content

Commit bbbc1f5

Browse files
author
Sriya Pratipati
committed
updated behavior to match POSIX
1 parent 4921132 commit bbbc1f5

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed

libc/src/wchar/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ add_entrypoint_object(
7676
libc.hdr.types.wchar_t
7777
libc.src.__support.common
7878
libc.src.__support.macros.config
79+
libc.src.__support.libc_errno
7980
libc.src.__support.wchar.mbrtowc
8081
libc.src.__support.wchar.mbstate
8182
)

libc/src/wchar/mbtowc.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "hdr/types/size_t.h"
1212
#include "hdr/types/wchar_t.h"
1313
#include "src/__support/common.h"
14+
#include "src/__support/libc_errno.h"
1415
#include "src/__support/macros/config.h"
1516
#include "src/__support/wchar/mbrtowc.h"
1617
#include "src/__support/wchar/mbstate.h"
@@ -20,12 +21,17 @@ namespace LIBC_NAMESPACE_DECL {
2021
LLVM_LIBC_FUNCTION(int, mbtowc,
2122
(wchar_t *__restrict pwc, const char *__restrict s,
2223
size_t n)) {
24+
// returns 0 since UTF-8 encoding is not state-dependent
2325
if (s == nullptr)
2426
return 0;
2527
internal::mbstate internal_mbstate;
26-
auto ret = internal::mbrtowc(pwc, s, n, &internal_mbstate);
28+
// temp ptr to use if pwc is nullptr
29+
wchar_t buf[1];
30+
auto ret =
31+
internal::mbrtowc(pwc == nullptr ? buf : pwc, s, n, &internal_mbstate);
2732
if (!ret.has_value() || static_cast<int>(ret.value()) == -2) {
2833
// Encoding failure
34+
libc_errno = EILSEQ;
2935
return -1;
3036
}
3137
return static_cast<int>(ret.value());

libc/test/src/wchar/mbtowc_test.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "hdr/types/wchar_t.h"
10+
#include "src/__support/libc_errno.h"
1011
#include "src/wchar/mbtowc.h"
1112
#include "test/UnitTest/Test.h"
1213

@@ -20,6 +21,7 @@ TEST(LlvmLibcMBToWC, OneByte) {
2021
// Should fail since we have not read enough
2122
n = LIBC_NAMESPACE::mbtowc(dest, ch, 0);
2223
ASSERT_EQ(n, -1);
24+
ASSERT_EQ(static_cast<int>(libc_errno), EILSEQ);
2325
}
2426

2527
TEST(LlvmLibcMBToWC, TwoByte) {
@@ -36,6 +38,7 @@ TEST(LlvmLibcMBToWC, TwoByte) {
3638
// Should fail after trying to read next byte too
3739
n = LIBC_NAMESPACE::mbtowc(dest, ch + 1, 1);
3840
ASSERT_EQ(n, -1);
41+
ASSERT_EQ(static_cast<int>(libc_errno), EILSEQ);
3942
}
4043

4144
TEST(LlvmLibcMBToWC, ThreeByte) {
@@ -49,6 +52,7 @@ TEST(LlvmLibcMBToWC, ThreeByte) {
4952
// Should fail since we have not read enough
5053
n = LIBC_NAMESPACE::mbtowc(dest, ch, 2);
5154
ASSERT_EQ(n, -1);
55+
ASSERT_EQ(static_cast<int>(libc_errno), EILSEQ);
5256
}
5357

5458
TEST(LlvmLibcMBToWC, FourByte) {
@@ -63,13 +67,15 @@ TEST(LlvmLibcMBToWC, FourByte) {
6367
// Should fail since we have not read enough
6468
n = LIBC_NAMESPACE::mbtowc(dest, ch, 2);
6569
ASSERT_EQ(n, -1);
70+
ASSERT_EQ(static_cast<int>(libc_errno), EILSEQ);
6671
}
6772

6873
TEST(LlvmLibcMBToWC, InvalidByte) {
6974
const char ch[1] = {static_cast<char>(0x80)};
7075
wchar_t dest[2];
7176
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 1);
7277
ASSERT_EQ(n, -1);
78+
ASSERT_EQ(static_cast<int>(libc_errno), EILSEQ);
7379
}
7480

7581
TEST(LlvmLibcMBToWC, InvalidMultiByte) {
@@ -80,6 +86,8 @@ TEST(LlvmLibcMBToWC, InvalidMultiByte) {
8086
// Trying to push all 4 should error
8187
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 4);
8288
ASSERT_EQ(n, -1);
89+
ASSERT_EQ(static_cast<int>(libc_errno), EILSEQ);
90+
8391
// Trying to push the second and third should correspond to null wc
8492
n = LIBC_NAMESPACE::mbtowc(dest, ch + 1, 2);
8593
ASSERT_EQ(n, 0);
@@ -95,6 +103,7 @@ TEST(LlvmLibcMBToWC, InvalidLastByte) {
95103
// Trying to push all 4 should error
96104
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 4);
97105
ASSERT_EQ(n, -1);
106+
ASSERT_EQ(static_cast<int>(libc_errno), EILSEQ);
98107
}
99108

100109
TEST(LlvmLibcMBToWC, ValidTwoByteWithExtraRead) {
@@ -130,3 +139,13 @@ TEST(LlvmLibcMBToWC, NullString) {
130139
n = LIBC_NAMESPACE::mbtowc(dest, ch, 1);
131140
ASSERT_EQ(n, 0);
132141
}
142+
143+
TEST(LlvmLibcMBToWC, NullWCPtr) {
144+
const char ch[2] = {
145+
static_cast<char>(0xC2),
146+
static_cast<char>(0x8E),
147+
};
148+
// a null destination should still return the number of read bytes
149+
int n = LIBC_NAMESPACE::mbtowc(nullptr, ch, 2);
150+
ASSERT_EQ(n, 2);
151+
}

0 commit comments

Comments
 (0)