OSDN Git Service

Hide various mbstate implementation details.
authorElliott Hughes <enh@google.com>
Sat, 15 Jul 2017 00:00:05 +0000 (17:00 -0700)
committerElliott Hughes <enh@google.com>
Sat, 15 Jul 2017 00:00:05 +0000 (17:00 -0700)
...by inlining them.

Also fix a couple of harmless bugs in passing. I've added tests, but in
both cases I don't think it was actually possible to hit the bad behavior:
we'd hit another test and fail immediately after in an externally
indistinguishable way.

Bug: N/A
Test: readelf
Change-Id: I8466050b0bfe2b7b94c76b383cf10c1d9d28debd

libc/Android.bp
libc/bionic/c16rtomb.cpp
libc/bionic/c32rtomb.cpp
libc/bionic/mbrtoc16.cpp
libc/bionic/mbrtoc32.cpp
libc/bionic/mbstate.cpp [deleted file]
libc/bionic/wchar.cpp
libc/private/bionic_mbstate.h
tests/uchar_test.cpp
tests/wchar_test.cpp

index 845945a..7b0ac23 100644 (file)
@@ -1409,7 +1409,6 @@ cc_library_static {
         "bionic/mblen.cpp",
         "bionic/mbrtoc16.cpp",
         "bionic/mbrtoc32.cpp",
-        "bionic/mbstate.cpp",
         "bionic/memmem.cpp",
         "bionic/mempcpy.cpp",
         "bionic/mkdir.cpp",
index 77512be..93749c6 100644 (file)
@@ -50,18 +50,18 @@ size_t c16rtomb(char* s, char16_t c16, mbstate_t* ps) {
       mbstate_set_byte(state, 2, (c32 & 0x00ff00) >> 8);
       return 0;
     } else if (is_low_surrogate(c16)) {
-      return reset_and_return_illegal(EINVAL, state);
+      return mbstate_reset_and_return_illegal(EINVAL, state);
     } else {
       return c32rtomb(s, static_cast<char32_t>(c16), state);
     }
   } else {
     if (!is_low_surrogate(c16)) {
-      return reset_and_return_illegal(EINVAL, state);
+      return mbstate_reset_and_return_illegal(EINVAL, state);
     }
 
     char32_t c32 = ((mbstate_get_byte(state, 3) << 16) |
                     (mbstate_get_byte(state, 2) << 8) |
                     (c16 & ~0xdc00)) + 0x10000;
-    return reset_and_return(c32rtomb(s, c32, NULL), state);
+    return mbstate_reset_and_return(c32rtomb(s, c32, NULL), state);
   }
 }
index d3231c0..ebe9cd3 100644 (file)
@@ -38,7 +38,7 @@ size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps) {
 
   if (s == NULL) {
     // Equivalent to c32rtomb(buf, U'\0', ps).
-    return reset_and_return(1, state);
+    return mbstate_reset_and_return(1, state);
   }
 
   // POSIX states that if char32_t is a null wide character, a null byte shall
@@ -47,11 +47,11 @@ size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps) {
   // stored.
   if (c32 == U'\0') {
     *s = '\0';
-    reset_and_return(1, state);
+    return mbstate_reset_and_return(1, state);
   }
 
   if (!mbsinit(state)) {
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   if ((c32 & ~0x7f) == 0) {
index 6878a11..2180516 100644 (file)
@@ -55,7 +55,7 @@ static size_t finish_surrogate(char16_t* pc16, mbstate_t* state) {
   char16_t trail = mbstate_get_byte(state, 1) << 8 |
                    mbstate_get_byte(state, 0);
   *pc16 = trail;
-  return reset_and_return(mbstate_get_byte(state, 3), state);
+  return mbstate_reset_and_return(mbstate_get_byte(state, 3), state);
 }
 
 size_t mbrtoc16(char16_t* pc16, const char* s, size_t n, mbstate_t* ps) {
@@ -76,13 +76,13 @@ size_t mbrtoc16(char16_t* pc16, const char* s, size_t n, mbstate_t* ps) {
   if (__MB_IS_ERR(nconv)) {
     return nconv;
   } else if (nconv == 0) {
-    return reset_and_return(nconv, state);
+    return mbstate_reset_and_return(nconv, state);
   } else if (c32 > 0x10ffff) {
     // Input cannot be encoded as UTF-16.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   } else if (c32 < 0x10000) {
     *pc16 = static_cast<char16_t>(c32);
-    return reset_and_return(nconv, state);
+    return mbstate_reset_and_return(nconv, state);
   } else {
     return begin_surrogate(c32, pc16, nconv, state);
   }
index bd40ecf..f004b78 100644 (file)
@@ -41,7 +41,7 @@ size_t mbrtoc32(char32_t* pc32, const char* s, size_t n, mbstate_t* ps) {
   // Full state verification is done when decoding the sequence (after we have
   // all the bytes).
   if (mbstate_get_byte(state, 3) != 0) {
-    return reset_and_return_illegal(EINVAL, state);
+    return mbstate_reset_and_return_illegal(EINVAL, state);
   }
 
   if (s == NULL) {
@@ -98,7 +98,7 @@ size_t mbrtoc32(char32_t* pc32, const char* s, size_t n, mbstate_t* ps) {
     lower_bound = 0x10000;
   } else {
     // Malformed input; input is not UTF-8. See RFC 3629.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   // Fill in the state.
@@ -107,7 +107,7 @@ size_t mbrtoc32(char32_t* pc32, const char* s, size_t n, mbstate_t* ps) {
   for (i = 0; i < MIN(bytes_wanted, n); i++) {
     if (!mbsinit(state) && ((*s & 0xc0) != 0x80)) {
       // Malformed input; bad characters in the middle of a character.
-      return reset_and_return_illegal(EILSEQ, state);
+      return mbstate_reset_and_return_illegal(EILSEQ, state);
     }
     mbstate_set_byte(state, bytes_so_far + i, *s++);
   }
@@ -125,14 +125,14 @@ size_t mbrtoc32(char32_t* pc32, const char* s, size_t n, mbstate_t* ps) {
 
   if (c32 < lower_bound) {
     // Malformed input; redundant encoding.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
   if ((c32 >= 0xd800 && c32 <= 0xdfff) || c32 == 0xfffe || c32 == 0xffff) {
     // Malformed input; invalid code points.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
   if (pc32 != NULL) {
     *pc32 = c32;
   }
-  return reset_and_return(c32 == U'\0' ? 0 : bytes_wanted, state);
+  return mbstate_reset_and_return(c32 == U'\0' ? 0 : bytes_wanted, state);
 }
diff --git a/libc/bionic/mbstate.cpp b/libc/bionic/mbstate.cpp
deleted file mode 100644 (file)
index cb327d8..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#include "private/bionic_mbstate.h"
-
-#include <errno.h>
-
-__LIBC_HIDDEN__ size_t mbstate_bytes_so_far(const mbstate_t* ps) {
-  return
-    (ps->__seq[2] != 0) ? 3 :
-    (ps->__seq[1] != 0) ? 2 :
-    (ps->__seq[0] != 0) ? 1 : 0;
-}
-
-__LIBC_HIDDEN__ void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
-  ps->__seq[i] = static_cast<uint8_t>(byte);
-}
-
-__LIBC_HIDDEN__ uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
-  return ps->__seq[n];
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return_illegal(int _errno, mbstate_t* ps) {
-  errno = _errno;
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return __MB_ERR_ILLEGAL_SEQUENCE;
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return(int _return, mbstate_t* ps) {
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return _return;
-}
index 36fc2a2..62023d6 100644 (file)
@@ -74,7 +74,7 @@ size_t mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len, mbstat
   // 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);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   // Measure only?
@@ -83,23 +83,23 @@ size_t mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len, mbstat
       if (static_cast<uint8_t>((*src)[i]) < 0x80) {
         // Fast path for plain ASCII characters.
         if ((*src)[i] == '\0') {
-          return reset_and_return(o, state);
+          return mbstate_reset_and_return(o, state);
         }
         r = 1;
       } else {
         r = mbrtowc(NULL, *src + i, nmc - i, state);
         if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
-          return reset_and_return_illegal(EILSEQ, state);
+          return mbstate_reset_and_return_illegal(EILSEQ, state);
         }
         if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
-          return reset_and_return_illegal(EILSEQ, state);
+          return mbstate_reset_and_return_illegal(EILSEQ, state);
         }
         if (r == 0) {
-          return reset_and_return(o, state);
+          return mbstate_reset_and_return(o, state);
         }
       }
     }
-    return reset_and_return(o, state);
+    return mbstate_reset_and_return(o, state);
   }
 
   // Actually convert, updating `dst` and `src`.
@@ -110,26 +110,26 @@ size_t mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len, mbstat
       r = 1;
       if ((*src)[i] == '\0') {
         *src = nullptr;
-        return reset_and_return(o, state);
+        return mbstate_reset_and_return(o, state);
       }
     } else {
       r = mbrtowc(dst + o, *src + i, nmc - i, state);
       if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
         *src += i;
-        return reset_and_return_illegal(EILSEQ, state);
+        return mbstate_reset_and_return_illegal(EILSEQ, state);
       }
       if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
         *src += nmc;
-        return reset_and_return(EILSEQ, state);
+        return mbstate_reset_and_return_illegal(EILSEQ, state);
       }
       if (r == 0) {
         *src = NULL;
-        return reset_and_return(o, state);
+        return mbstate_reset_and_return(o, state);
       }
     }
   }
   *src += i;
-  return reset_and_return(o, state);
+  return mbstate_reset_and_return(o, state);
 }
 
 size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) {
@@ -149,7 +149,7 @@ size_t wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len, mbstat
   mbstate_t* state = (ps == NULL) ? &__private_state : ps;
 
   if (!mbsinit(state)) {
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   char buf[MB_LEN_MAX];
index 018b47c..292959a 100644 (file)
@@ -43,11 +43,31 @@ __BEGIN_DECLS
 #define __MB_IS_ERR(rv) (rv == __MB_ERR_ILLEGAL_SEQUENCE || \
                          rv == __MB_ERR_INCOMPLETE_SEQUENCE)
 
-size_t mbstate_bytes_so_far(const mbstate_t* ps);
-void mbstate_set_byte(mbstate_t* ps, int i, char byte);
-uint8_t mbstate_get_byte(const mbstate_t* ps, int n);
-size_t reset_and_return_illegal(int _errno, mbstate_t* ps);
-size_t reset_and_return(int _return, mbstate_t* ps);
+static inline __wur size_t mbstate_bytes_so_far(const mbstate_t* ps) {
+  return
+      (ps->__seq[2] != 0) ? 3 :
+      (ps->__seq[1] != 0) ? 2 :
+      (ps->__seq[0] != 0) ? 1 : 0;
+}
+
+static inline void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
+  ps->__seq[i] = static_cast<uint8_t>(byte);
+}
+
+static inline __wur uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
+  return ps->__seq[n];
+}
+
+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;
+}
+
+static inline __wur size_t mbstate_reset_and_return(int _return, mbstate_t* ps) {
+  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
+  return _return;
+}
 
 __END_DECLS
 
index c887f8a..8b29667 100644 (file)
@@ -280,7 +280,10 @@ TEST(uchar, c32rtomb) {
 
   char bytes[MB_LEN_MAX];
 
+  memset(bytes, 1, sizeof(bytes));
   EXPECT_EQ(1U, c32rtomb(bytes, L'\0', NULL));
+  EXPECT_EQ('\0', bytes[0]);
+  EXPECT_EQ('\x01', bytes[1]);
 
   memset(bytes, 0, sizeof(bytes));
   EXPECT_EQ(1U, c32rtomb(bytes, L'h', NULL));
@@ -408,4 +411,3 @@ TEST(uchar, mbrtoc32_incomplete) {
   GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
 #endif
 }
-
index 830eb70..097647f 100644 (file)
@@ -445,6 +445,18 @@ TEST(wchar, mbsnrtowcs) {
   ASSERT_EQ(L'e', dst[1]);
   ASSERT_EQ(L'l', dst[2]);
   ASSERT_EQ(&s[3], src);
+
+  memset(dst, 0, sizeof(dst));
+  const char* incomplete = "\xc2"; // Incomplete UTF-8 sequence.
+  src = incomplete;
+  errno = 0;
+  ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(dst, &src, SIZE_MAX, 3, nullptr));
+  ASSERT_EQ(EILSEQ, errno);
+
+  src = incomplete;
+  errno = 0;
+  ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(nullptr, &src, SIZE_MAX, 3, nullptr));
+  ASSERT_EQ(EILSEQ, errno);
 }
 
 TEST(wchar, wcsftime) {