--- /dev/null
+Index: /trunk/icu4c/source/common/utext.cpp\r
+===================================================================\r
+--- a/common/utext.cpp (revision 39670)\r
++++ b/common/utext.cpp (revision 39671)\r
+@@ -848,7 +848,13 @@\r
+ \r
+ // Chunk size.\r
+-// Must be less than 85, because of byte mapping from UChar indexes to native indexes.\r
+-// Worst case is three native bytes to one UChar. (Supplemenaries are 4 native bytes\r
+-// to two UChars.)\r
++// Must be less than 42 (256/6), because of byte mapping from UChar indexes to native indexes.\r
++// Worst case there are six UTF-8 bytes per UChar.\r
++// obsolete 6 byte form fd + 5 trails maps to fffd\r
++// obsolete 5 byte form fc + 4 trails maps to fffd\r
++// non-shortest 4 byte forms maps to fffd\r
++// normal supplementaries map to a pair of utf-16, two utf8 bytes per utf-16 unit\r
++// mapToUChars array size must allow for the worst case, 6.\r
++// This could be brought down to 4, by treating fd and fc as pure illegal,\r
++// rather than obsolete lead bytes. But that is not compatible with the utf-8 access macros.\r
+ //\r
+ enum { UTF8_TEXT_CHUNK_SIZE=32 };\r
+@@ -890,5 +896,5 @@\r
+ // one for a supplementary starting in the last normal position,\r
+ // and one for an entry for the buffer limit position.\r
+- uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to\r
++ uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*6+6]; // Map native offset from bufNativeStart to\r
+ // correspoding offset in filled part of buf.\r
+ int32_t align;\r
+@@ -1033,4 +1039,5 @@\r
+ u8b = (UTF8Buf *)ut->p; // the current buffer\r
+ mapIndex = ix - u8b->toUCharsMapStart;\r
++ U_ASSERT(mapIndex < (int32_t)sizeof(UTF8Buf::mapToUChars));\r
+ ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;\r
+ return TRUE;\r
+@@ -1299,4 +1306,8 @@\r
+ // If index is at the end, there is no character there to look at.\r
+ if (ix != ut->b) {\r
++ // Note: this function will only move the index back if it is on a trail byte\r
++ // and there is a preceding lead byte and the sequence from the lead \r
++ // through this trail could be part of a valid UTF-8 sequence\r
++ // Otherwise the index remains unchanged.\r
+ U8_SET_CP_START(s8, 0, ix);\r
+ }\r
+@@ -1312,5 +1323,8 @@\r
+ uint8_t *mapToNative = u8b->mapToNative;\r
+ uint8_t *mapToUChars = u8b->mapToUChars;\r
+- int32_t toUCharsMapStart = ix - (UTF8_TEXT_CHUNK_SIZE*3 + 1);\r
++ int32_t toUCharsMapStart = ix - sizeof(UTF8Buf::mapToUChars) + 1;\r
++ // Note that toUCharsMapStart can be negative. Happens when the remaining\r
++ // text from current position to the beginning is less than the buffer size.\r
++ // + 1 because mapToUChars must have a slot at the end for the bufNativeLimit entry.\r
+ int32_t destIx = UTF8_TEXT_CHUNK_SIZE+2; // Start in the overflow region\r
+ // at end of buffer to leave room\r
+@@ -1339,4 +1353,5 @@\r
+ // Special case ASCII range for speed.\r
+ buf[destIx] = (UChar)c;\r
++ U_ASSERT(toUCharsMapStart <= srcIx);\r
+ mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx;\r
+ mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);\r
+@@ -1368,4 +1383,5 @@\r
+ mapToUChars[sIx-- - toUCharsMapStart] = (uint8_t)destIx;\r
+ } while (sIx >= srcIx);\r
++ U_ASSERT(toUCharsMapStart <= (srcIx+1));\r
+ \r
+ // Set native indexing limit to be the current position.\r
+@@ -1542,4 +1558,5 @@\r
+ U_ASSERT(index<=ut->chunkNativeLimit);\r
+ int32_t mapIndex = index - u8b->toUCharsMapStart;\r
++ U_ASSERT(mapIndex < (int32_t)sizeof(UTF8Buf::mapToUChars));\r
+ int32_t offset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;\r
+ U_ASSERT(offset>=0 && offset<=ut->chunkLength);\r
+Index: /trunk/icu4c/source/test/intltest/utxttest.cpp\r
+===================================================================\r
+--- a/test/intltest/utxttest.cpp (revision 39670)\r
++++ b/test/intltest/utxttest.cpp (revision 39671)\r
+@@ -68,4 +68,6 @@\r
+ case 7: name = "Ticket12130";\r
+ if (exec) Ticket12130(); break;\r
++ case 8: name = "Ticket12888";\r
++ if (exec) Ticket12888(); break;\r
+ default: name = ""; break;\r
+ }\r
+@@ -1584,2 +1586,62 @@\r
+ utext_close(&ut);\r
+ }\r
++\r
++// Ticket 12888: bad handling of illegal utf-8 containing many instances of the archaic, now illegal,\r
++// six byte utf-8 forms. Original implementation had an assumption that\r
++// there would be at most three utf-8 bytes per UTF-16 code unit.\r
++// The five and six byte sequences map to a single replacement character.\r
++\r
++void UTextTest::Ticket12888() {\r
++ const char *badString = \r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"\r
++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80";\r
++\r
++ UErrorCode status = U_ZERO_ERROR;\r
++ LocalUTextPointer ut(utext_openUTF8(NULL, badString, -1, &status));\r
++ TEST_SUCCESS(status);\r
++ for (;;) {\r
++ UChar32 c = utext_next32(ut.getAlias());\r
++ if (c == U_SENTINEL) {\r
++ break;\r
++ }\r
++ }\r
++ int32_t endIdx = utext_getNativeIndex(ut.getAlias());\r
++ if (endIdx != (int32_t)strlen(badString)) {\r
++ errln("%s:%d expected=%d, actual=%d", __FILE__, __LINE__, strlen(badString), endIdx);\r
++ return;\r
++ }\r
++\r
++ for (int32_t prevIndex = endIdx; prevIndex>0;) {\r
++ UChar32 c = utext_previous32(ut.getAlias());\r
++ int32_t currentIndex = utext_getNativeIndex(ut.getAlias());\r
++ if (c != 0xfffd) {\r
++ errln("%s:%d (expected, actual, index) = (%d, %d, %d)\n",\r
++ __FILE__, __LINE__, 0xfffd, c, currentIndex);\r
++ break;\r
++ }\r
++ if (currentIndex != prevIndex - 6) {\r
++ errln("%s:%d: wrong index. Expected, actual = %d, %d",\r
++ __FILE__, __LINE__, prevIndex - 6, currentIndex);\r
++ break;\r
++ }\r
++ prevIndex = currentIndex;\r
++ }\r
++}\r
+Index: /trunk/icu4c/source/test/intltest/utxttest.h\r
+===================================================================\r
+--- a/test/intltest/utxttest.h (revision 39670)\r
++++ b/test/intltest/utxttest.h (revision 39671)\r
+@@ -39,4 +39,5 @@\r
+ void Ticket10983();\r
+ void Ticket12130();\r
++ void Ticket12888();\r
+ \r
+ private:\r
--- /dev/null
+# Copyright 1999-2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=6
+
+inherit eutils flag-o-matic toolchain-funcs autotools multilib-minimal
+
+DESCRIPTION="International Components for Unicode"
+HOMEPAGE="http://www.icu-project.org/"
+SRC_URI="http://download.icu-project.org/files/icu4c/${PV/_/}/icu4c-${PV//./_}-src.tgz"
+
+LICENSE="BSD"
+
+SLOT="0/${PV}"
+
+KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86 ~amd64-fbsd ~x86-fbsd"
+IUSE="debug doc examples static-libs"
+
+DEPEND="
+ virtual/pkgconfig
+ doc? (
+ app-doc/doxygen[dot]
+ )
+"
+
+S="${WORKDIR}/${PN}/source"
+
+MULTILIB_CHOST_TOOLS=(
+ /usr/bin/icu-config
+)
+
+PATCHES=(
+ "${FILESDIR}/${PN}-58.1-remove-bashisms.patch"
+ "${FILESDIR}/${PN}-58.1-iterator.patch"
+ "${FILESDIR}/${PN}-58.2-CVE-2017-7867.patch"
+)
+
+pkg_pretend() {
+ if tc-is-gcc ; then
+ if [[ $(gcc-major-version) == 4 && $(gcc-minor-version) -lt 9 \
+ || $(gcc-major-version) -lt 4 ]] ; then
+ die "You need at least sys-devel/gcc-4.9"
+ fi
+ fi
+}
+
+src_prepare() {
+ # apply patches
+ default
+
+ local variable
+
+ # Disable renaming as it is stupid thing to do
+ sed -i \
+ -e "s/#define U_DISABLE_RENAMING 0/#define U_DISABLE_RENAMING 1/" \
+ common/unicode/uconfig.h || die
+
+ # Fix linking of icudata
+ sed -i \
+ -e "s:LDFLAGSICUDT=-nodefaultlibs -nostdlib:LDFLAGSICUDT=:" \
+ config/mh-linux || die
+
+ # Append doxygen configuration to configure
+ sed -i \
+ -e 's:icudefs.mk:icudefs.mk Doxyfile:' \
+ configure.ac || die
+
+ eautoreconf
+}
+
+src_configure() {
+ # Use C++14
+ append-cxxflags -std=c++14
+
+ if tc-is-gcc ; then
+ if [[ $(gcc-major-version) == 4 && $(gcc-minor-version) -lt 9 \
+ || $(gcc-major-version) -lt 4 ]] ; then
+ die "You need at least sys-devel/gcc-4.9"
+ fi
+ fi
+
+ if tc-is-cross-compiler; then
+ mkdir "${WORKDIR}"/host || die
+ pushd "${WORKDIR}"/host >/dev/null || die
+
+ CFLAGS="" CXXFLAGS="" ASFLAGS="" LDFLAGS="" \
+ CC="$(tc-getBUILD_CC)" CXX="$(tc-getBUILD_CXX)" AR="$(tc-getBUILD_AR)" \
+ RANLIB="$(tc-getBUILD_RANLIB)" LD="$(tc-getBUILD_LD)" \
+ "${S}"/configure --disable-renaming --disable-debug \
+ --disable-samples --enable-static || die
+ emake
+
+ popd >/dev/null || die
+ fi
+
+ multilib-minimal_src_configure
+}
+
+multilib_src_configure() {
+ local myeconfargs=(
+ --disable-renaming
+ --disable-samples
+ --disable-layoutex
+ $(use_enable debug)
+ $(use_enable static-libs static)
+ )
+
+ multilib_is_native_abi && myeconfargs+=(
+ $(use_enable examples samples)
+ )
+ tc-is-cross-compiler && myeconfargs+=(
+ --with-cross-build="${WORKDIR}"/host
+ )
+
+ # icu tries to use clang by default
+ tc-export CC CXX
+
+ ECONF_SOURCE=${S} \
+ econf "${myeconfargs[@]}"
+}
+
+multilib_src_compile() {
+ default
+
+ if multilib_is_native_abi && use doc; then
+ doxygen -u Doxyfile || die
+ doxygen Doxyfile || die
+ fi
+}
+
+multilib_src_test() {
+ # INTLTEST_OPTS: intltest options
+ # -e: Exhaustive testing
+ # -l: Reporting of memory leaks
+ # -v: Increased verbosity
+ # IOTEST_OPTS: iotest options
+ # -e: Exhaustive testing
+ # -v: Increased verbosity
+ # CINTLTST_OPTS: cintltst options
+ # -e: Exhaustive testing
+ # -v: Increased verbosity
+ emake -j1 VERBOSE="1" check
+}
+
+multilib_src_install() {
+ default
+
+ if multilib_is_native_abi && use doc; then
+ docinto html
+ dodoc -r doc/html/*
+ fi
+}
+
+multilib_src_install_all() {
+ einstalldocs
+ docinto html
+ dodoc ../readme.html
+}