Merge "Add the L() macro for local labels to <private/bionic_asm.h>." into main
diff --git a/libc/bionic/c32rtomb.cpp b/libc/bionic/c32rtomb.cpp
index 4fa76ff..a7cd207 100644
--- a/libc/bionic/c32rtomb.cpp
+++ b/libc/bionic/c32rtomb.cpp
@@ -78,7 +78,7 @@
length = 4;
} else {
errno = EILSEQ;
- return __MB_ERR_ILLEGAL_SEQUENCE;
+ return BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE;
}
// Output the octets representing the character in chunks
diff --git a/libc/bionic/iconv.cpp b/libc/bionic/iconv.cpp
index 79a429c..5bff50a 100644
--- a/libc/bionic/iconv.cpp
+++ b/libc/bionic/iconv.cpp
@@ -160,9 +160,9 @@
case UTF_8:
src_bytes_used = mbrtoc32(&wc, *src_buf, *src_bytes_left, &ps);
- if (src_bytes_used == __MB_ERR_ILLEGAL_SEQUENCE) {
+ if (src_bytes_used == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
break; // EILSEQ already set.
- } else if (src_bytes_used == __MB_ERR_INCOMPLETE_SEQUENCE) {
+ } else if (src_bytes_used == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
errno = EINVAL;
return false;
}
@@ -235,9 +235,9 @@
case UTF_8:
dst_bytes_used = c32rtomb(buf, wc, &ps);
- if (dst_bytes_used == __MB_ERR_ILLEGAL_SEQUENCE) {
+ if (dst_bytes_used == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
break; // EILSEQ already set.
- } else if (dst_bytes_used == __MB_ERR_INCOMPLETE_SEQUENCE) {
+ } else if (dst_bytes_used == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
errno = EINVAL;
return false;
}
diff --git a/libc/bionic/malloc_limit.cpp b/libc/bionic/malloc_limit.cpp
index 1405a39..deb63f4 100644
--- a/libc/bionic/malloc_limit.cpp
+++ b/libc/bionic/malloc_limit.cpp
@@ -278,7 +278,7 @@
// being called, allow a short period for the signal handler to complete
// before failing.
bool enabled = false;
- size_t num_tries = 20;
+ size_t num_tries = 200;
while (true) {
if (!atomic_exchange(&gGlobalsMutating, true)) {
__libc_globals.mutate([](libc_globals* globals) {
@@ -328,9 +328,16 @@
current_allocated = Malloc(mallinfo)().uordblks;
}
#endif
+ // This has to be set before the enable occurs since "gAllocated" is used
+ // to compute the limit. If the enable fails, "gAllocated" is never used.
atomic_store(&gAllocated, current_allocated);
- return EnableLimitDispatchTable();
+ if (!EnableLimitDispatchTable()) {
+ // Failed to enable, reset so a future enable will pass.
+ atomic_store(&limit_enabled, false);
+ return false;
+ }
+ return true;
}
static size_t LimitUsableSize(const void* mem) {
diff --git a/libc/bionic/mbrtoc32.cpp b/libc/bionic/mbrtoc32.cpp
index d37ca66..c26dd71 100644
--- a/libc/bionic/mbrtoc32.cpp
+++ b/libc/bionic/mbrtoc32.cpp
@@ -109,7 +109,7 @@
mbstate_set_byte(state, bytes_so_far + i, *s++);
}
if (i < bytes_wanted) {
- return __MB_ERR_INCOMPLETE_SEQUENCE;
+ return BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE;
}
// Decode the octet sequence representing the character in chunks
diff --git a/libc/bionic/wchar.cpp b/libc/bionic/wchar.cpp
index bb97b3e..b8c4432 100644
--- a/libc/bionic/wchar.cpp
+++ b/libc/bionic/wchar.cpp
@@ -27,10 +27,10 @@
*/
#include <errno.h>
-#include <sys/param.h>
#include <string.h>
-#include <wchar.h>
+#include <sys/param.h>
#include <uchar.h>
+#include <wchar.h>
#include "private/bionic_mbstate.h"
@@ -88,10 +88,10 @@
r = 1;
} else {
r = mbrtowc(nullptr, *src + i, nmc - i, state);
- if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+ if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
return mbstate_reset_and_return_illegal(EILSEQ, state);
}
- if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
+ if (r == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
return mbstate_reset_and_return_illegal(EILSEQ, state);
}
if (r == 0) {
@@ -114,11 +114,11 @@
}
} else {
r = mbrtowc(dst + o, *src + i, nmc - i, state);
- if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+ if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
*src += i;
return mbstate_reset_and_return_illegal(EILSEQ, state);
}
- if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
+ if (r == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
*src += nmc;
return mbstate_reset_and_return_illegal(EILSEQ, state);
}
@@ -166,7 +166,7 @@
r = 1;
} else {
r = wcrtomb(buf, wc, state);
- if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+ if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
return r;
}
}
@@ -187,14 +187,14 @@
} else if (len - o >= sizeof(buf)) {
// Enough space to translate in-place.
r = wcrtomb(dst + o, wc, state);
- if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+ if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
*src += i;
return r;
}
} else {
// May not be enough space; use temp buffer.
r = wcrtomb(buf, wc, state);
- if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+ if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
*src += i;
return r;
}
diff --git a/libc/include/bits/bionic_multibyte_result.h b/libc/include/bits/bionic_multibyte_result.h
new file mode 100644
index 0000000..0d5cf21
--- /dev/null
+++ b/libc/include/bits/bionic_multibyte_result.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+/**
+ * @file bits/bionic_multibyte_result.h
+ * @brief Named values for the magic number return values of multibyte
+ * conversion APIs defined by C.
+ */
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * @brief The error values defined by C for multibyte conversion APIs.
+ *
+ * Refer to C23 7.30.1 Restartable multibyte/wide character conversion functions
+ * for more details.
+ */
+enum : size_t {
+ /// @brief An encoding error occurred. The bytes read are not a valid unicode
+ /// character, nor are they a partially valid character.
+ BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE = -1UL,
+#define BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE
+
+ /// @brief The bytes read may produce a valid unicode character, but the
+ /// sequence is incomplete. Future calls may complete the character.
+ BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE = -2UL,
+#define BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE
+
+ /// @brief The output of the call was the result of a previous successful
+ /// decoding. No new bytes were consumed.
+ ///
+ /// The common case for this return value is when mbrtoc16 returns the low
+ /// surrogate of a pair.
+ BIONIC_MULTIBYTE_RESULT_NO_BYTES_CONSUMED = -3UL,
+#define BIONIC_MULTIBYTE_RESULT_NO_BYTES_CONSUMED BIONIC_MULTIBYTE_RESULT_NO_BYTES_CONSUMED
+};
+
+__END_DECLS
diff --git a/libc/include/uchar.h b/libc/include/uchar.h
index 0c7424d..626372a 100644
--- a/libc/include/uchar.h
+++ b/libc/include/uchar.h
@@ -35,6 +35,8 @@
#include <stddef.h>
#include <sys/cdefs.h>
+
+#include <bits/bionic_multibyte_result.h>
#include <bits/mbstate_t.h>
__BEGIN_DECLS
diff --git a/libc/include/wchar.h b/libc/include/wchar.h
index 2671580..c4e9679 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -37,6 +37,7 @@
#include <time.h>
#include <xlocale.h>
+#include <bits/bionic_multibyte_result.h>
#include <bits/mbstate_t.h>
#include <bits/wchar_limits.h>
#include <bits/wctype.h>
diff --git a/libc/private/bionic_mbstate.h b/libc/private/bionic_mbstate.h
index 243b220..29f5aa6 100644
--- a/libc/private/bionic_mbstate.h
+++ b/libc/private/bionic_mbstate.h
@@ -34,15 +34,9 @@
__BEGIN_DECLS
-/*
- * These return values are specified by POSIX for multibyte conversion
- * functions.
- */
-#define __MB_ERR_ILLEGAL_SEQUENCE static_cast<size_t>(-1)
-#define __MB_ERR_INCOMPLETE_SEQUENCE static_cast<size_t>(-2)
-
-#define __MB_IS_ERR(rv) (rv == __MB_ERR_ILLEGAL_SEQUENCE || \
- rv == __MB_ERR_INCOMPLETE_SEQUENCE)
+#define __MB_IS_ERR(rv) \
+ (rv == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE || \
+ rv == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE)
static inline __wur bool mbstate_is_initial(const mbstate_t* ps) {
return *(reinterpret_cast<const uint32_t*>(ps->__seq)) == 0;
@@ -66,10 +60,10 @@
static inline __wur size_t mbstate_reset_and_return_illegal(int _errno, mbstate_t* ps) {
errno = _errno;
*(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
- return __MB_ERR_ILLEGAL_SEQUENCE;
+ return BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE;
}
-static inline __wur size_t mbstate_reset_and_return(int _return, mbstate_t* ps) {
+static inline __wur size_t mbstate_reset_and_return(size_t _return, mbstate_t* ps) {
*(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
return _return;
}
diff --git a/libc/stdio/vfscanf.cpp b/libc/stdio/vfscanf.cpp
index 3133f1f..3607995 100644
--- a/libc/stdio/vfscanf.cpp
+++ b/libc/stdio/vfscanf.cpp
@@ -327,12 +327,12 @@
fp->_r--;
memset(&mbs, 0, sizeof(mbs));
nconv = mbrtowc(wcp, buf, bytes, &mbs);
- if (nconv == __MB_ERR_ILLEGAL_SEQUENCE) {
+ if (nconv == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
fp->_flags |= __SERR;
goto input_failure;
}
if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
- if (nconv != __MB_ERR_INCOMPLETE_SEQUENCE) {
+ if (nconv != BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
nread += bytes;
width--;
if (!(flags & SUPPRESS)) wcp++;
@@ -417,11 +417,11 @@
wchar_t wc = L'\0';
memset(&mbs, 0, sizeof(mbs));
nconv = mbrtowc(&wc, buf, bytes, &mbs);
- if (nconv == __MB_ERR_ILLEGAL_SEQUENCE) {
+ if (nconv == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
fp->_flags |= __SERR;
goto input_failure;
}
- if (nconv != __MB_ERR_INCOMPLETE_SEQUENCE) {
+ if (nconv != BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
if ((c == CT_CCL && wctob(wc) != EOF && !ccltab[wctob(wc)]) || (c == CT_STRING && iswspace(wc))) {
while (bytes != 0) {
bytes--;
diff --git a/libm/NOTICE b/libm/NOTICE
index 5e2f8ca..31337e7 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -1176,6 +1176,32 @@
-------------------------------------------------------------------
+Copyright (c) 2017, 2023 Steven G. Kargl
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice unmodified, this list of conditions, and the following
+ disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
From: @(#)s_ilogb.c 5.1 93/09/24
====================================================
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 2dbc680..776643d 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -1384,7 +1384,7 @@
threads[i]->join();
}
ASSERT_EQ(1U, num_successful) << "Only one thread should be able to set the limit.";
- exit(0);
+ _exit(0);
}
#endif
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 8716810..04932ba 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -29,6 +29,62 @@
#define NUM_WCHARS(num_bytes) ((num_bytes)/sizeof(wchar_t))
+#ifdef __GLIBC__
+// glibc immediately dereferences the locale passed to all wcsto*_l functions,
+// even if it won't be used, and even if it's LC_GLOBAL_LOCALE, which isn't a
+// pointer to valid memory.
+static locale_t SAFE_LC_GLOBAL_LOCALE = duplocale(LC_GLOBAL_LOCALE);
+#else
+static locale_t SAFE_LC_GLOBAL_LOCALE = LC_GLOBAL_LOCALE;
+#endif
+
+// Modern versions of UTF-8 (https://datatracker.ietf.org/doc/html/rfc3629 and
+// newer) explicitly disallow code points beyond U+10FFFF, which exclude all 5-
+// and 6-byte sequences. Earlier versions of UTF-8 allowed the wider range:
+// https://datatracker.ietf.org/doc/html/rfc2279.
+//
+// Bionic's unicode implementation was written after the high values were
+// excluded, so it has never supported them. Other implementations (at least
+// as of glibc 2.36), do support those sequences.
+#if defined(__ANDROID__) || defined(ANDROID_HOST_MUSL)
+constexpr bool kLibcRejectsOverLongUtf8Sequences = true;
+#elif defined(__GLIBC__)
+constexpr bool kLibcRejectsOverLongUtf8Sequences = false;
+#else
+#error kLibcRejectsOverLongUtf8Sequences must be configured for this platform
+#endif
+
+// C23 7.31.6.3.2 (mbrtowc) says:
+//
+// Returns:
+//
+// 0 if the next n or fewer bytes complete the multibyte character that
+// corresponds to the null wide character (which is the value stored).
+//
+// (size_t)(-2) if the next n bytes contribute to an incomplete (but
+// potentially valid) multibyte character, and all n bytes have been
+// processed (no value is stored).
+//
+// Bionic historically interpreted the behavior when n is 0 to be the next 0
+// bytes decoding to the null. That's a pretty bad interpretation, and both
+// glibc and musl return -2 for that case.
+//
+// The tests currently checks the incorrect behavior for bionic because gtest
+// doesn't support explicit xfail annotations. The behavior difference here
+// should be fixed, but danalbert wants to add more tests before tackling the
+// bugs.
+#ifdef __ANDROID__
+constexpr size_t kExpectedResultForZeroLength = 0U;
+#else
+constexpr size_t kExpectedResultForZeroLength = static_cast<size_t>(-2);
+#endif
+
+#if defined(__GLIBC__)
+constexpr bool kLibcSupportsParsingBinaryLiterals = __GLIBC_PREREQ(2, 38);
+#else
+constexpr bool kLibcSupportsParsingBinaryLiterals = true;
+#endif
+
TEST(wchar, sizeof_wchar_t) {
EXPECT_EQ(4U, sizeof(wchar_t));
EXPECT_EQ(4U, sizeof(wint_t));
@@ -36,7 +92,7 @@
TEST(wchar, mbrlen) {
char bytes[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
- EXPECT_EQ(0U, mbrlen(&bytes[0], 0, nullptr));
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrlen(&bytes[0], 0, nullptr));
EXPECT_EQ(1U, mbrlen(&bytes[0], 1, nullptr));
EXPECT_EQ(1U, mbrlen(&bytes[4], 1, nullptr));
@@ -95,6 +151,9 @@
}
TEST(wchar, wcrtomb_start_state) {
+ ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+ uselocale(LC_GLOBAL_LOCALE);
+
char out[MB_LEN_MAX];
mbstate_t ps;
@@ -118,6 +177,9 @@
}
TEST(wchar, wcstombs_wcrtombs) {
+ ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+ uselocale(LC_GLOBAL_LOCALE);
+
const wchar_t chars[] = { L'h', L'e', L'l', L'l', L'o', 0 };
const wchar_t bad_chars[] = { L'h', L'i', static_cast<wchar_t>(0xffffffff), 0 };
const wchar_t* src;
@@ -255,63 +317,98 @@
TEST(wchar, mbtowc) {
wchar_t out[8];
+ // bionic has the same misunderstanding of the result for a zero-length
+ // conversion for mbtowc as it does for all the other multibyte conversion
+ // functions but mbtowc returns different values than all the others:
+ //
+ // C23 7.24.7.2.4:
+ //
+ // If s is a null pointer, the mbtowc function returns a nonzero or zero
+ // value, if multibyte character encodings, respectively, do or do not have
+ // state-dependent encodings. If s is not a null pointer, the mbtowc function
+ // either returns 0 (if s points to the null character), or returns the number
+ // of bytes that are contained in the converted multibyte character (if the
+ // next n or fewer bytes form a valid multibyte character), or returns -1 (if
+ // they do not form a valid multibyte character).
+
+#ifdef __BIONIC__
+ int expected_result_for_zero_length = 0;
+#else
+ int expected_result_for_zero_length = -1;
+#endif
+
out[0] = 'x';
- ASSERT_EQ(0, mbtowc(out, "hello", 0));
- ASSERT_EQ('x', out[0]);
+ EXPECT_EQ(expected_result_for_zero_length, mbtowc(out, "hello", 0));
+ EXPECT_EQ('x', out[0]);
- ASSERT_EQ(0, mbtowc(out, "hello", 0));
- ASSERT_EQ(0, mbtowc(out, "", 0));
- ASSERT_EQ(1, mbtowc(out, "hello", 1));
- ASSERT_EQ(L'h', out[0]);
+ EXPECT_EQ(expected_result_for_zero_length, mbtowc(out, "hello", 0));
+ EXPECT_EQ(0, mbtowc(out, "", 0));
+ EXPECT_EQ(1, mbtowc(out, "hello", 1));
+ EXPECT_EQ(L'h', out[0]);
- ASSERT_EQ(0, mbtowc(nullptr, "hello", 0));
- ASSERT_EQ(0, mbtowc(nullptr, "", 0));
- ASSERT_EQ(1, mbtowc(nullptr, "hello", 1));
+ EXPECT_EQ(expected_result_for_zero_length, mbtowc(nullptr, "hello", 0));
+ EXPECT_EQ(0, mbtowc(nullptr, "", 0));
+ EXPECT_EQ(1, mbtowc(nullptr, "hello", 1));
- ASSERT_EQ(0, mbtowc(nullptr, nullptr, 0));
+ EXPECT_EQ(0, mbtowc(nullptr, nullptr, 0));
}
TEST(wchar, mbrtowc) {
wchar_t out[8];
out[0] = 'x';
- ASSERT_EQ(0U, mbrtowc(out, "hello", 0, nullptr));
- ASSERT_EQ('x', out[0]);
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(out, "hello", 0, nullptr));
+ EXPECT_EQ('x', out[0]);
- ASSERT_EQ(0U, mbrtowc(out, "hello", 0, nullptr));
- ASSERT_EQ(0U, mbrtowc(out, "", 0, nullptr));
- ASSERT_EQ(1U, mbrtowc(out, "hello", 1, nullptr));
- ASSERT_EQ(L'h', out[0]);
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(out, "hello", 0, nullptr));
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(out, "", 0, nullptr));
+ EXPECT_EQ(1U, mbrtowc(out, "hello", 1, nullptr));
+ EXPECT_EQ(L'h', out[0]);
- ASSERT_EQ(0U, mbrtowc(nullptr, "hello", 0, nullptr));
- ASSERT_EQ(0U, mbrtowc(nullptr, "", 0, nullptr));
- ASSERT_EQ(1U, mbrtowc(nullptr, "hello", 1, nullptr));
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(nullptr, "hello", 0, nullptr));
+ EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(nullptr, "", 0, nullptr));
+ EXPECT_EQ(1U, mbrtowc(nullptr, "hello", 1, nullptr));
- ASSERT_EQ(0U, mbrtowc(nullptr, nullptr, 0, nullptr));
+ EXPECT_EQ(0U, mbrtowc(nullptr, nullptr, 0, nullptr));
- ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+ EXPECT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
// 1-byte UTF-8.
- ASSERT_EQ(1U, mbrtowc(out, "abcdef", 6, nullptr));
- ASSERT_EQ(L'a', out[0]);
+ EXPECT_EQ(1U, mbrtowc(out, "abcdef", 6, nullptr));
+ EXPECT_EQ(L'a', out[0]);
// 2-byte UTF-8.
- ASSERT_EQ(2U, mbrtowc(out, "\xc2\xa2" "cdef", 6, nullptr));
- ASSERT_EQ(static_cast<wchar_t>(0x00a2), out[0]);
+ EXPECT_EQ(2U, mbrtowc(out,
+ "\xc2\xa2"
+ "cdef",
+ 6, nullptr));
+ EXPECT_EQ(static_cast<wchar_t>(0x00a2), out[0]);
// 3-byte UTF-8.
- ASSERT_EQ(3U, mbrtowc(out, "\xe2\x82\xac" "def", 6, nullptr));
- ASSERT_EQ(static_cast<wchar_t>(0x20ac), out[0]);
+ EXPECT_EQ(3U, mbrtowc(out,
+ "\xe2\x82\xac"
+ "def",
+ 6, nullptr));
+ EXPECT_EQ(static_cast<wchar_t>(0x20ac), out[0]);
// 4-byte UTF-8.
- ASSERT_EQ(4U, mbrtowc(out, "\xf0\xa4\xad\xa2" "ef", 6, nullptr));
- ASSERT_EQ(static_cast<wchar_t>(0x24b62), out[0]);
+ EXPECT_EQ(4U, mbrtowc(out,
+ "\xf0\xa4\xad\xa2"
+ "ef",
+ 6, nullptr));
+ EXPECT_EQ(static_cast<wchar_t>(0x24b62), out[0]);
#if defined(__BIONIC__) // glibc allows this.
// Illegal 5-byte UTF-8.
- ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf8\xa1\xa2\xa3\xa4" "f", 6, nullptr));
- ASSERT_EQ(EILSEQ, errno);
+ EXPECT_EQ(static_cast<size_t>(-1), mbrtowc(out,
+ "\xf8\xa1\xa2\xa3\xa4"
+ "f",
+ 6, nullptr));
+ EXPECT_EQ(EILSEQ, errno);
#endif
// Illegal over-long sequence.
- ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf0\x82\x82\xac" "ef", 6, nullptr));
- ASSERT_EQ(EILSEQ, errno);
+ EXPECT_EQ(static_cast<size_t>(-1), mbrtowc(out,
+ "\xf0\x82\x82\xac"
+ "ef",
+ 6, nullptr));
+ EXPECT_EQ(EILSEQ, errno);
}
TEST(wchar, mbrtowc_valid_non_characters) {
@@ -332,8 +429,14 @@
wchar_t out[8] = {};
errno = 0;
- ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf5\x80\x80\x80", 4, nullptr));
- ASSERT_EQ(EILSEQ, errno);
+ auto result = mbrtowc(out, "\xf5\x80\x80\x80", 4, nullptr);
+ if (kLibcRejectsOverLongUtf8Sequences) {
+ ASSERT_EQ(static_cast<size_t>(-1), result);
+ ASSERT_EQ(EILSEQ, errno);
+ } else {
+ ASSERT_EQ(4U, result);
+ ASSERT_EQ(0, errno);
+ }
}
static void test_mbrtowc_incomplete(mbstate_t* ps) {
@@ -446,8 +549,8 @@
void TestSingleWcsToInt(WcsToIntFn<T> fn, const wchar_t* str, int base,
T expected_value, ptrdiff_t expected_len) {
wchar_t* p;
- ASSERT_EQ(expected_value, fn(str, &p, base));
- ASSERT_EQ(expected_len, p - str) << str;
+ EXPECT_EQ(expected_value, fn(str, &p, base)) << str << " " << base;
+ EXPECT_EQ(expected_len, p - str) << str << " " << base;
}
template <typename T>
@@ -460,7 +563,9 @@
TestSingleWcsToInt(fn, L" 123 45", 0, static_cast<T>(123), 6);
TestSingleWcsToInt(fn, L" -123", 0, static_cast<T>(-123), 6);
TestSingleWcsToInt(fn, L"0x10000", 0, static_cast<T>(65536), 7);
- TestSingleWcsToInt(fn, L"0b1011", 0, static_cast<T>(0b1011), 6);
+ if (kLibcSupportsParsingBinaryLiterals) {
+ TestSingleWcsToInt(fn, L"0b1011", 0, static_cast<T>(0b1011), 6);
+ }
}
template <typename T>
@@ -584,7 +689,7 @@
EXPECT_EQ(24U, wcsftime(buf, sizeof(buf), L"%c", &t));
EXPECT_STREQ(L"Sun Mar 10 00:00:00 2100", buf);
- EXPECT_EQ(24U, wcsftime_l(buf, sizeof(buf), L"%c", &t, LC_GLOBAL_LOCALE));
+ EXPECT_EQ(24U, wcsftime_l(buf, sizeof(buf), L"%c", &t, SAFE_LC_GLOBAL_LOCALE));
EXPECT_STREQ(L"Sun Mar 10 00:00:00 2100", buf);
}
@@ -781,25 +886,25 @@
TEST(wchar, wcstoll_l_EINVAL) {
errno = 0;
- wcstoll_l(L"123", nullptr, -1, LC_GLOBAL_LOCALE);
+ wcstoll_l(L"123", nullptr, -1, SAFE_LC_GLOBAL_LOCALE);
ASSERT_EQ(EINVAL, errno);
errno = 0;
- wcstoll_l(L"123", nullptr, 1, LC_GLOBAL_LOCALE);
+ wcstoll_l(L"123", nullptr, 1, SAFE_LC_GLOBAL_LOCALE);
ASSERT_EQ(EINVAL, errno);
errno = 0;
- wcstoll_l(L"123", nullptr, 37, LC_GLOBAL_LOCALE);
+ wcstoll_l(L"123", nullptr, 37, SAFE_LC_GLOBAL_LOCALE);
ASSERT_EQ(EINVAL, errno);
}
TEST(wchar, wcstoull_l_EINVAL) {
errno = 0;
- wcstoull_l(L"123", nullptr, -1, LC_GLOBAL_LOCALE);
+ wcstoull_l(L"123", nullptr, -1, SAFE_LC_GLOBAL_LOCALE);
ASSERT_EQ(EINVAL, errno);
errno = 0;
- wcstoull_l(L"123", nullptr, 1, LC_GLOBAL_LOCALE);
+ wcstoull_l(L"123", nullptr, 1, SAFE_LC_GLOBAL_LOCALE);
ASSERT_EQ(EINVAL, errno);
errno = 0;
- wcstoull_l(L"123", nullptr, 37, LC_GLOBAL_LOCALE);
+ wcstoull_l(L"123", nullptr, 37, SAFE_LC_GLOBAL_LOCALE);
ASSERT_EQ(EINVAL, errno);
}
@@ -922,7 +1027,7 @@
TEST(wchar, wcstod_l) {
#if !defined(ANDROID_HOST_MUSL)
- EXPECT_EQ(1.23, wcstod_l(L"1.23", nullptr, LC_GLOBAL_LOCALE));
+ EXPECT_EQ(1.23, wcstod_l(L"1.23", nullptr, SAFE_LC_GLOBAL_LOCALE));
#else
GTEST_SKIP() << "musl doesn't have wcstod_l";
#endif
@@ -930,7 +1035,7 @@
TEST(wchar, wcstof_l) {
#if !defined(ANDROID_HOST_MUSL)
- EXPECT_EQ(1.23f, wcstof_l(L"1.23", nullptr, LC_GLOBAL_LOCALE));
+ EXPECT_EQ(1.23f, wcstof_l(L"1.23", nullptr, SAFE_LC_GLOBAL_LOCALE));
#else
GTEST_SKIP() << "musl doesn't have wcstof_l";
#endif
@@ -938,30 +1043,30 @@
TEST(wchar, wcstol_l) {
#if !defined(ANDROID_HOST_MUSL)
- EXPECT_EQ(123L, wcstol_l(L"123", nullptr, 10, LC_GLOBAL_LOCALE));
+ EXPECT_EQ(123L, wcstol_l(L"123", nullptr, 10, SAFE_LC_GLOBAL_LOCALE));
#else
GTEST_SKIP() << "musl doesn't have wcstol_l";
#endif
}
TEST(wchar, wcstold_l) {
- EXPECT_EQ(1.23L, wcstold_l(L"1.23", nullptr, LC_GLOBAL_LOCALE));
+ EXPECT_EQ(1.23L, wcstold_l(L"1.23", nullptr, SAFE_LC_GLOBAL_LOCALE));
}
TEST(wchar, wcstoll_l) {
- EXPECT_EQ(123LL, wcstoll_l(L"123", nullptr, 10, LC_GLOBAL_LOCALE));
+ EXPECT_EQ(123LL, wcstoll_l(L"123", nullptr, 10, SAFE_LC_GLOBAL_LOCALE));
}
TEST(wchar, wcstoul_l) {
#if !defined(ANDROID_HOST_MUSL)
- EXPECT_EQ(123UL, wcstoul_l(L"123", nullptr, 10, LC_GLOBAL_LOCALE));
+ EXPECT_EQ(123UL, wcstoul_l(L"123", nullptr, 10, SAFE_LC_GLOBAL_LOCALE));
#else
GTEST_SKIP() << "musl doesn't have wcstoul_l";
#endif
}
TEST(wchar, wcstoull_l) {
- EXPECT_EQ(123ULL, wcstoull_l(L"123", nullptr, 10, LC_GLOBAL_LOCALE));
+ EXPECT_EQ(123ULL, wcstoull_l(L"123", nullptr, 10, SAFE_LC_GLOBAL_LOCALE));
}
static void AssertWcwidthRange(wchar_t begin, wchar_t end, int expected) {