Fix mbsnrtowcs where `dst` is null.
POSIX is its usual unintelligible self
(http://pubs.opengroup.org/onlinepubs/9699919799/functions/mbsrtowcs.html),
but the ISO C11 standard (7.29.6.4.1 paragraph 2) is pretty clear: *src
should change if and only if dst is non-null.
Bug: https://code.google.com/p/android/issues/detail?id=166381
Test: bionic tests
Change-Id: Ibc631cfa5b1bf4a6f56963feba9f0eea27b07984
diff --git a/libc/bionic/wchar.cpp b/libc/bionic/wchar.cpp
index e0879b9..d28888d 100644
--- a/libc/bionic/wchar.cpp
+++ b/libc/bionic/wchar.cpp
@@ -70,21 +70,19 @@
mbstate_t* state = (ps == NULL) ? &__private_state : ps;
size_t i, o, r;
+ // The fast paths in the loops below are not safe if an ASCII
+ // character appears as anything but the first byte of a
+ // multibyte sequence. Check now to avoid doing it in the loops.
+ if (nmc > 0 && mbstate_bytes_so_far(state) > 0 && static_cast<uint8_t>((*src)[0]) < 0x80) {
+ return reset_and_return_illegal(EILSEQ, state);
+ }
+
+ // Measure only?
if (dst == NULL) {
- /*
- * The fast path in the loop below is not safe if an ASCII
- * character appears as anything but the first byte of a
- * multibyte sequence. Check now to avoid doing it in the loop.
- */
- if ((nmc > 0) && (mbstate_bytes_so_far(state) > 0)
- && (static_cast<uint8_t>((*src)[0]) < 0x80)) {
- return reset_and_return_illegal(EILSEQ, state);
- }
for (i = o = 0; i < nmc; i += r, o++) {
if (static_cast<uint8_t>((*src)[i]) < 0x80) {
// Fast path for plain ASCII characters.
if ((*src)[i] == '\0') {
- *src = nullptr;
return reset_and_return(o, state);
}
r = 1;
@@ -97,7 +95,6 @@
return reset_and_return_illegal(EILSEQ, state);
}
if (r == 0) {
- *src = nullptr;
return reset_and_return(o, state);
}
}
@@ -105,15 +102,7 @@
return reset_and_return(o, state);
}
- /*
- * The fast path in the loop below is not safe if an ASCII
- * character appears as anything but the first byte of a
- * multibyte sequence. Check now to avoid doing it in the loop.
- */
- if ((nmc > 0) && (mbstate_bytes_so_far(state) > 0)
- && (static_cast<uint8_t>((*src)[0]) < 0x80)) {
- return reset_and_return_illegal(EILSEQ, state);
- }
+ // Actually convert, updating `dst` and `src`.
for (i = o = 0; i < nmc && o < len; i += r, o++) {
if (static_cast<uint8_t>((*src)[i]) < 0x80) {
// Fast path for plain ASCII characters.
@@ -151,7 +140,7 @@
static mbstate_t __private_state;
mbstate_t* state = (ps == NULL) ? &__private_state : ps;
- // Our wchar_t is UTF-32
+ // Our wchar_t is UTF-32.
return c32rtomb(s, static_cast<char32_t>(wc), state);
}