--- old/src/java.desktop/share/legal/harfbuzz.md 2018-07-05 09:24:17.429223203 -0700 +++ new/src/java.desktop/share/legal/harfbuzz.md 2018-07-05 09:24:17.301223208 -0700 @@ -1,4 +1,4 @@ -## Harfbuzz v1.8.1 +## Harfbuzz v1.8.2 ### Harfbuzz License --- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc 2018-07-05 09:24:18.697223154 -0700 +++ new/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc 2018-07-05 09:24:18.569223159 -0700 @@ -489,10 +489,10 @@ #if defined(_WIN32) || defined(__CYGWIN__) # include -#endif - -#ifndef _O_BINARY -# define _O_BINARY 0 +#else +# ifndef _O_BINARY +# define _O_BINARY 0 +# endif #endif #ifndef MAP_NORESERVE @@ -517,7 +517,7 @@ UnmapViewOfFile (file->contents); CloseHandle (file->mapping); #else - free (file->contents); + assert (0); // If we don't have mmap we shouldn't reach here #endif free (file); @@ -534,77 +534,103 @@ hb_blob_t * hb_blob_create_from_file (const char *file_name) { - // Adopted from glib's gmappedfile.c with Matthias Clasen and - // Allison Lortie permission but changed a lot to suit our need. - bool writable = false; - hb_memory_mode_t mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE; + /* Adopted from glib's gmappedfile.c with Matthias Clasen and + Allison Lortie permission but changed a lot to suit our need. */ +#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); if (unlikely (!file)) return hb_blob_get_empty (); -#ifdef HAVE_MMAP - int fd = open (file_name, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0); -# define CLOSE close + int fd = open (file_name, O_RDONLY | _O_BINARY, 0); if (unlikely (fd == -1)) goto fail_without_close; struct stat st; if (unlikely (fstat (fd, &st) == -1)) goto fail; - // See https://github.com/GNOME/glib/blob/f9faac7/glib/gmappedfile.c#L139-L142 - if (unlikely (st.st_size == 0 && S_ISREG (st.st_mode))) goto fail; - file->length = (unsigned long) st.st_size; - file->contents = (char *) mmap (nullptr, file->length, - writable ? PROT_READ|PROT_WRITE : PROT_READ, + file->contents = (char *) mmap (nullptr, file->length, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0); if (unlikely (file->contents == MAP_FAILED)) goto fail; -#elif defined(_WIN32) || defined(__CYGWIN__) - HANDLE fd = CreateFile (file_name, - writable ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, nullptr, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr); -# define CLOSE CloseHandle + close (fd); - if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; - - file->length = (unsigned long) GetFileSize (fd, nullptr); - file->mapping = CreateFileMapping (fd, nullptr, - writable ? PAGE_WRITECOPY : PAGE_READONLY, - 0, 0, nullptr); - if (unlikely (file->mapping == nullptr)) goto fail; + return hb_blob_create (file->contents, file->length, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, + (hb_destroy_func_t) _hb_mapped_file_destroy); - file->contents = (char *) MapViewOfFile (file->mapping, - writable ? FILE_MAP_COPY : FILE_MAP_READ, - 0, 0, 0); - if (unlikely (file->contents == nullptr)) goto fail; +fail: + close (fd); +fail_without_close: + free (file); -#else - mm = HB_MEMORY_MODE_WRITABLE; +#elif (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP) + hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); + if (unlikely (!file)) return hb_blob_get_empty (); - FILE *fd = fopen (file_name, "rb"); -# define CLOSE fclose - if (unlikely (!fd)) goto fail_without_close; + HANDLE fd = CreateFile (file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, + nullptr); - fseek (fd, 0, SEEK_END); - file->length = ftell (fd); - rewind (fd); - file->contents = (char *) malloc (file->length); - if (unlikely (!file->contents)) goto fail; + if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; - if (unlikely (fread (file->contents, 1, file->length, fd) != file->length)) - goto fail; + file->length = (unsigned long) GetFileSize (fd, nullptr); + file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); + if (unlikely (file->mapping == nullptr)) goto fail; -#endif + file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); + if (unlikely (file->contents == nullptr)) goto fail; - CLOSE (fd); - return hb_blob_create (file->contents, file->length, mm, (void *) file, + CloseHandle (fd); + return hb_blob_create (file->contents, file->length, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, (hb_destroy_func_t) _hb_mapped_file_destroy); fail: - CLOSE (fd); -#undef CLOSE + CloseHandle (fd); fail_without_close: free (file); + +#endif + + /* The following tries to read a file without knowing its size beforehand + It's used as a fallback for systems without mmap or to read from pipes */ + unsigned long len = 0, allocated = BUFSIZ * 16; + char *data = (char *) malloc (allocated); + if (unlikely (data == nullptr)) return hb_blob_get_empty (); + + FILE *fp = fopen (file_name, "rb"); + if (unlikely (fp == nullptr)) goto fread_fail_without_close; + + while (!feof (fp)) + { + if (allocated - len < BUFSIZ) + { + allocated *= 2; + /* Don't allocate and go more than ~536MB, our mmap reader still + can cover files like that but lets limit our fallback reader */ + if (unlikely (allocated > (2 << 28))) goto fread_fail; + char *new_data = (char *) realloc (data, allocated); + if (unlikely (new_data == nullptr)) goto fread_fail; + data = new_data; + } + + unsigned long addition = fread (data + len, 1, allocated - len, fp); + + int err = ferror (fp); +#ifdef EINTR // armcc doesn't have it + if (unlikely (err == EINTR)) continue; +#endif + if (unlikely (err)) goto fread_fail; + + len += addition; + } + + return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data, + (hb_destroy_func_t) free); + +fread_fail: + fclose (fp); +fread_fail_without_close: + free (data); return hb_blob_get_empty (); } --- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-file-private.hh 2018-07-05 09:24:19.105223139 -0700 +++ new/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-file-private.hh 2018-07-05 09:24:18.973223144 -0700 @@ -286,6 +286,197 @@ } u; }; +/* + * Mac Resource Fork + */ + +struct ResourceRefItem +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + // actual data sanitization is done on ResourceForkHeader sanitizer + return_trace (likely (c->check_struct (this))); + } + + HBINT16 id; /* Resource ID, is really should be signed? */ + HBINT16 nameOffset; /* Offset from beginning of resource name list + * to resource name, minus means there is no */ + HBUINT8 attr; /* Resource attributes */ + HBUINT24 dataOffset; /* Offset from beginning of resource data to + * data for this resource */ + HBUINT32 reserved; /* Reserved for handle to resource */ + public: + DEFINE_SIZE_STATIC (12); +}; + +struct ResourceTypeItem +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + // RefList sanitization is done on ResourceMap sanitizer + return_trace (likely (c->check_struct (this))); + } + + inline unsigned int get_resource_count () const + { + return numRes + 1; + } + + inline bool is_sfnt () const + { + return type == HB_TAG ('s','f','n','t'); + } + + inline const ResourceRefItem& get_ref_item (const void *base, + unsigned int i) const + { + return (base+refList)[i]; + } + + protected: + Tag type; /* Resource type */ + HBUINT16 numRes; /* Number of resource this type in map minus 1 */ + OffsetTo > + refList; /* Offset from beginning of resource type list + * to reference list for this type */ + public: + DEFINE_SIZE_STATIC (8); +}; + +struct ResourceMap +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + for (unsigned int i = 0; i < get_types_count (); ++i) + { + const ResourceTypeItem& type = get_type (i); + if (unlikely (!type.sanitize (c))) + return_trace (false); + for (unsigned int j = 0; j < type.get_resource_count (); ++j) + if (unlikely (!get_ref_item (type, j).sanitize (c))) + return_trace (false); + } + return_trace (true); + } + + inline const ResourceTypeItem& get_type (unsigned int i) const + { + // Why offset from the second byte of the object? I'm not sure + return ((&reserved[2])+typeList)[i]; + } + + inline unsigned int get_types_count () const + { + return nTypes + 1; + } + + inline const ResourceRefItem &get_ref_item (const ResourceTypeItem &type, + unsigned int i) const + { + return type.get_ref_item (&(this+typeList), i); + } + + inline const PString& get_name (const ResourceRefItem &item, + unsigned int i) const + { + if (item.nameOffset == -1) + return Null (PString); + + return StructAtOffset (this, nameList + item.nameOffset); + } + + protected: + HBUINT8 reserved[16]; /* Reserved for copy of resource header */ + LOffsetTo + reserved1; /* Reserved for handle to next resource map */ + HBUINT16 reserved2; /* Reserved for file reference number */ + HBUINT16 attr; /* Resource fork attribute */ + OffsetTo > + typeList; /* Offset from beginning of map to + * resource type list */ + HBUINT16 nameList; /* Offset from beginning of map to + * resource name list */ + HBUINT16 nTypes; /* Number of types in the map minus 1 */ + public: + DEFINE_SIZE_STATIC (30); +}; + +struct ResourceForkHeader +{ + inline unsigned int get_face_count () const + { + const ResourceMap &resource_map = this+map; + for (unsigned int i = 0; i < resource_map.get_types_count (); ++i) + { + const ResourceTypeItem& type = resource_map.get_type (i); + if (type.is_sfnt ()) + return type.get_resource_count (); + } + return 0; + } + + inline const LArrayOf& get_data (const ResourceTypeItem& type, + unsigned int idx) const + { + const ResourceMap &resource_map = this+map; + unsigned int offset = dataOffset; + offset += resource_map.get_ref_item (type, idx).dataOffset; + return StructAtOffset > (this, offset); + } + + inline const OpenTypeFontFace& get_face (unsigned int idx) const + { + const ResourceMap &resource_map = this+map; + for (unsigned int i = 0; i < resource_map.get_types_count (); ++i) + { + const ResourceTypeItem& type = resource_map.get_type (i); + if (type.is_sfnt () && idx < type.get_resource_count ()) + return (OpenTypeFontFace&) get_data (type, idx).arrayZ; + } + return Null (OpenTypeFontFace); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + + const ResourceMap &resource_map = this+map; + if (unlikely (!resource_map.sanitize (c))) + return_trace (false); + + for (unsigned int i = 0; i < resource_map.get_types_count (); ++i) + { + const ResourceTypeItem& type = resource_map.get_type (i); + for (unsigned int j = 0; j < type.get_resource_count (); ++j) + { + const LArrayOf& data = get_data (type, j); + if (unlikely (!(data.sanitize (c) && + ((OpenTypeFontFace&) data.arrayZ).sanitize (c)))) + return_trace (false); + } + } + + return_trace (true); + } + + protected: + HBUINT32 dataOffset; /* Offset from beginning of resource fork + * to resource data */ + LOffsetTo + map; /* Offset from beginning of resource fork + * to resource map */ + HBUINT32 dataLen; /* Length of resource data */ + HBUINT32 mapLen; /* Length of resource map */ + public: + DEFINE_SIZE_STATIC (16); +}; /* * OpenType Font File @@ -299,6 +490,7 @@ CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */ TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */ TTCTag = HB_TAG ('t','t','c','f'), /* TrueType Collection */ + DFontTag = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */ TrueTag = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */ Typ1Tag = HB_TAG ('t','y','p','1') /* Obsolete Apple Type1 font in SFNT container */ }; @@ -313,6 +505,7 @@ case Typ1Tag: case TrueTypeTag: return 1; case TTCTag: return u.ttcHeader.get_face_count (); +// case DFontTag: return u.rfHeader.get_face_count (); default: return 0; } } @@ -327,6 +520,7 @@ case Typ1Tag: case TrueTypeTag: return u.fontFace; case TTCTag: return u.ttcHeader.get_face (i); +// case DFontTag: return u.rfHeader.get_face (i); default: return Null(OpenTypeFontFace); } } @@ -353,6 +547,7 @@ case Typ1Tag: case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); case TTCTag: return_trace (u.ttcHeader.sanitize (c)); +// case DFontTag: return_trace (u.rfHeader.sanitize (c)); default: return_trace (true); } } @@ -362,6 +557,7 @@ Tag tag; /* 4-byte identifier. */ OpenTypeFontFace fontFace; TTCHeader ttcHeader; + ResourceForkHeader rfHeader; } u; public: DEFINE_SIZE_UNION (4, tag); --- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type-private.hh 2018-07-05 09:24:19.485223124 -0700 +++ new/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type-private.hh 2018-07-05 09:24:19.353223129 -0700 @@ -1033,6 +1033,7 @@ DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; template struct LArrayOf : ArrayOf {}; +typedef ArrayOf PString; /* Array of Offset's */ template --- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh 2018-07-05 09:24:19.849223110 -0700 +++ new/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh 2018-07-05 09:24:19.713223115 -0700 @@ -832,7 +832,12 @@ c = &c_; coverage = 0; i = 0; - j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; + j = c->rangeRecord.len ? c->rangeRecord[0].start : 0; + if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end)) + { + /* Broken table. Skip. */ + i = c->rangeRecord.len; + } } inline bool more (void) { return i < c->rangeRecord.len; } inline void next (void) @@ -842,7 +847,14 @@ i++; if (more ()) { + hb_codepoint_t old = j; j = c->rangeRecord[i].start; + if (unlikely (j <= old)) + { + /* Broken table. Skip. Important to avoid DoS. */ + i = c->rangeRecord.len; + return; + } coverage = c->rangeRecord[i].value; } return; @@ -855,7 +867,8 @@ private: const struct CoverageFormat2 *c; - unsigned int i, j, coverage; + unsigned int i, coverage; + hb_codepoint_t j; }; private: --- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gpos-table.hh 2018-07-05 09:24:20.245223095 -0700 +++ new/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gpos-table.hh 2018-07-05 09:24:20.117223100 -0700 @@ -1074,10 +1074,13 @@ if (!skippy_iter.prev ()) return_trace (false); /* We only want to attach to the first of a MultipleSubst sequence. * https://github.com/harfbuzz/harfbuzz/issues/740 - * Reject others. */ + * Reject others... + * ...but stop if we find a mark in the MultipleSubst sequence: + * https://github.com/harfbuzz/harfbuzz/issues/1020 */ if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) || 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) || (skippy_iter.idx == 0 || + _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) || _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) != _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) || _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) != --- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic.cc 2018-07-05 09:24:20.625223081 -0700 +++ new/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic.cc 2018-07-05 09:24:20.493223086 -0700 @@ -668,8 +668,9 @@ * * Reports suggest that in some scripts Uniscribe does this only if there * is *not* a Halant after last consonant already (eg. Kannada), while it - * does it unconditionally in other scripts (eg. Malayalam). We don't - * currently know about other scripts, so we single out Malayalam for now. + * does it unconditionally in other scripts (eg. Malayalam, Bengali). We + * don't currently know about other scripts, so we whitelist Malayalam and + * Bengali for now. * * Kannada test case: * U+0C9A,U+0CCD,U+0C9A,U+0CCD @@ -679,10 +680,16 @@ * Malayalam test case: * U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D * With lohit-ttf-20121122/Lohit-Malayalam.ttf + * + * Bengali test case + * U+0998,U+09CD,U+09AF,U+09CD + * With Windows XP vrinda.ttf + * https://github.com/harfbuzz/harfbuzz/issues/1073 */ if (indic_plan->is_old_spec) { - bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM; + bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM && + buffer->props.script != HB_SCRIPT_BENGALI; for (unsigned int i = base + 1; i < end; i++) if (info[i].indic_category() == OT_H) { --- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-khmer.cc 2018-07-05 09:24:20.997223066 -0700 +++ new/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-khmer.cc 2018-07-05 09:24:20.865223071 -0700 @@ -372,22 +372,25 @@ break; } - /* Note! syllable() is a one-byte field. */ - for (unsigned int i = base; i < end; i++) - if (info[i].syllable() != 255) - { - unsigned int max = i; - unsigned int j = start + info[i].syllable(); - while (j != i) + if (unlikely (end - start >= 127)) + buffer->merge_clusters (start, end); + else + /* Note! syllable() is a one-byte field. */ + for (unsigned int i = base; i < end; i++) + if (info[i].syllable() != 255) { - max = MAX (max, j); - unsigned int next = start + info[j].syllable(); - info[j].syllable() = 255; /* So we don't process j later again. */ - j = next; + unsigned int max = i; + unsigned int j = start + info[i].syllable(); + while (j != i) + { + max = MAX (max, j); + unsigned int next = start + info[j].syllable(); + info[j].syllable() = 255; /* So we don't process j later again. */ + j = next; + } + if (i != max) + buffer->merge_clusters (i, max + 1); } - if (i != max) - buffer->merge_clusters (i, max + 1); - } /* Put syllable back in. */ for (unsigned int i = start; i < end; i++) --- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-private.hh 2018-07-05 09:24:21.345223053 -0700 +++ new/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-private.hh 2018-07-05 09:24:21.213223058 -0700 @@ -1228,13 +1228,14 @@ /* fallback for round() */ #if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND) static inline double -round (double x) +_hb_round (double x) { if (x >= 0) return floor (x + 0.5); else return ceil (x - 0.5); } +#define round(x) _hb_round(x) #endif --- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-version.h 2018-07-05 09:24:21.977223029 -0700 +++ new/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-version.h 2018-07-05 09:24:21.689223040 -0700 @@ -38,9 +38,9 @@ #define HB_VERSION_MAJOR 1 #define HB_VERSION_MINOR 8 -#define HB_VERSION_MICRO 1 +#define HB_VERSION_MICRO 2 -#define HB_VERSION_STRING "1.8.1" +#define HB_VERSION_STRING "1.8.2" #define HB_VERSION_ATLEAST(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) <= \