From b134a80c36b973aa67072a542e9a01cf97975443 Mon Sep 17 00:00:00 2001 From: Mark H Weaver Date: Wed, 2 Mar 2016 14:36:25 -0500 Subject: [PATCH] gnu: icecat: Update bundled graphite2 to 1.3.6 [unspecified security fixes]. * gnu/packages/patches/icecat-update-graphite2-pt2.patch: New file. * gnu-system.am (dist_patch_DATA): Add it. * gnu/packages/gnuzilla.scm (icecat)[source]: Add patch. --- gnu-system.am | 1 + gnu/packages/gnuzilla.scm | 3 +- .../patches/icecat-update-graphite2-pt2.patch | 861 ++++++++++++++++++ 3 files changed, 864 insertions(+), 1 deletion(-) create mode 100644 gnu/packages/patches/icecat-update-graphite2-pt2.patch diff --git a/gnu-system.am b/gnu-system.am index 526e991beb..61ee02fdb4 100644 --- a/gnu-system.am +++ b/gnu-system.am @@ -525,6 +525,7 @@ dist_patch_DATA = \ gnu/packages/patches/hydra-disable-darcs-test.patch \ gnu/packages/patches/icecat-avoid-bundled-includes.patch \ gnu/packages/patches/icecat-update-graphite2.patch \ + gnu/packages/patches/icecat-update-graphite2-pt2.patch \ gnu/packages/patches/icecat-re-enable-DHE-cipher-suites.patch \ gnu/packages/patches/icu4c-CVE-2014-6585.patch \ gnu/packages/patches/icu4c-CVE-2015-1270.patch \ diff --git a/gnu/packages/gnuzilla.scm b/gnu/packages/gnuzilla.scm index ec97491cd7..1a2057a343 100644 --- a/gnu/packages/gnuzilla.scm +++ b/gnu/packages/gnuzilla.scm @@ -290,7 +290,8 @@ (define-public icecat (patches (map search-patch '("icecat-avoid-bundled-includes.patch" "icecat-re-enable-DHE-cipher-suites.patch" - "icecat-update-graphite2.patch"))) + "icecat-update-graphite2.patch" + "icecat-update-graphite2-pt2.patch"))) (modules '((guix build utils))) (snippet '(begin diff --git a/gnu/packages/patches/icecat-update-graphite2-pt2.patch b/gnu/packages/patches/icecat-update-graphite2-pt2.patch new file mode 100644 index 0000000000..8acde75d6c --- /dev/null +++ b/gnu/packages/patches/icecat-update-graphite2-pt2.patch @@ -0,0 +1,861 @@ +Copied from upstream: +https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/ec9cff7bb543 + +# HG changeset patch +# User Jonathan Kew +# Date 1456760339 0 +# Node ID ec9cff7bb5439b2b4c1249ff9376d07a80172c27 +# Parent 6f4d5130238790fa5810c76ffeb9eccc65efa8c9 +Bug 1248876 - Update graphite2 to upstream release 1.3.6. r=jrmuizel a=sledru + +diff --git a/gfx/graphite2/README.mozilla b/gfx/graphite2/README.mozilla +--- a/gfx/graphite2/README.mozilla ++++ b/gfx/graphite2/README.mozilla +@@ -1,7 +1,3 @@ +-This directory contains the Graphite2 library release 1.3.5 from +-https://github.com/silnrsi/graphite/releases/download/1.3.5/graphite2-minimal-1.3.5.tgz ++This directory contains the Graphite2 library release 1.3.6 from ++https://github.com/silnrsi/graphite/releases/download/1.3.6/graphite-minimal-1.3.6.tgz + See gfx/graphite2/moz-gr-update.sh for update procedure. +- +-Also includes two post-1.3.5 fixes: +-a8b3ac2aed0eb132cd80efe7de88f8153e73c829 +-e569e28d83491fedb31b9220493f3c07f6ec6d80 +diff --git a/gfx/graphite2/include/graphite2/Font.h b/gfx/graphite2/include/graphite2/Font.h +--- a/gfx/graphite2/include/graphite2/Font.h ++++ b/gfx/graphite2/include/graphite2/Font.h +@@ -25,17 +25,17 @@ + either version 2 of the License or (at your option) any later version. + */ + #pragma once + + #include "graphite2/Types.h" + + #define GR2_VERSION_MAJOR 1 + #define GR2_VERSION_MINOR 3 +-#define GR2_VERSION_BUGFIX 5 ++#define GR2_VERSION_BUGFIX 6 + + #ifdef __cplusplus + extern "C" + { + #endif + + typedef struct gr_face gr_face; + typedef struct gr_font gr_font; +diff --git a/gfx/graphite2/moz-gr-update.sh b/gfx/graphite2/moz-gr-update.sh +--- a/gfx/graphite2/moz-gr-update.sh ++++ b/gfx/graphite2/moz-gr-update.sh +@@ -14,17 +14,17 @@ + RELEASE=$1 + + if [ "x$RELEASE" == "x" ] + then + echo "Must provide the version number to be used." + exit 1 + fi + +-TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite2-minimal-$RELEASE.tgz" ++TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite-minimal-$RELEASE.tgz" + + foo=`basename $0` + TMPFILE=`mktemp -t ${foo}` || exit 1 + + curl -L "$TARBALL" -o "$TMPFILE" + tar -x -z -C gfx/graphite2/ --strip-components 1 -f "$TMPFILE" || exit 1 + rm "$TMPFILE" + +diff --git a/gfx/graphite2/src/CmapCache.cpp b/gfx/graphite2/src/CmapCache.cpp +--- a/gfx/graphite2/src/CmapCache.cpp ++++ b/gfx/graphite2/src/CmapCache.cpp +@@ -33,43 +33,43 @@ of the License or (at your option) any l + + + using namespace graphite2; + + const void * bmp_subtable(const Face::Table & cmap) + { + const void * stbl; + if (!cmap.size()) return 0; +- if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap.size()) +- || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap.size()) +- || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap.size()) +- || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap.size()) +- || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap.size())) ++ if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap + cmap.size()) ++ || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap + cmap.size()) ++ || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap + cmap.size()) ++ || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap + cmap.size()) ++ || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap + cmap.size())) + return stbl; + return 0; + } + + const void * smp_subtable(const Face::Table & cmap) + { + const void * stbl; + if (!cmap.size()) return 0; +- if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap.size()) +- || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap.size())) ++ if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap + cmap.size()) ++ || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap + cmap.size())) + return stbl; + return 0; + } + + template + bool cache_subtable(uint16 * blocks[], const void * cst, const unsigned int limit) + { + int rangeKey = 0; + uint32 codePoint = NextCodePoint(cst, 0, &rangeKey), + prevCodePoint = 0; +- while (codePoint != limit) ++ while (codePoint < limit) + { + unsigned int block = codePoint >> 8; + if (!blocks[block]) + { + blocks[block] = grzeroalloc(0x100); + if (!blocks[block]) + return false; + } +diff --git a/gfx/graphite2/src/Code.cpp b/gfx/graphite2/src/Code.cpp +--- a/gfx/graphite2/src/Code.cpp ++++ b/gfx/graphite2/src/Code.cpp +@@ -79,18 +79,19 @@ struct context + + + class Machine::Code::decoder + { + public: + struct limits; + struct analysis + { ++ static const int NUMCONTEXTS = 256; + uint8 slotref; +- context contexts[256]; ++ context contexts[NUMCONTEXTS]; + byte max_ref; + + analysis() : slotref(0), max_ref(0) {}; + void set_ref(int index, bool incinsert=false) throw(); + void set_noref(int index) throw(); + void set_changed(int index) throw(); + + }; +@@ -363,29 +364,33 @@ opcode Machine::Code::decoder::fetch_opc + break; + case ATTR_SET : + case ATTR_ADD : + case ATTR_SUB : + case ATTR_SET_SLOT : + if (--_stack_depth < 0) + failure(underfull_stack); + valid_upto(gr_slatMax, bc[0]); ++ if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes ++ failure(out_of_range_data); + test_context(); + break; + case IATTR_SET_SLOT : + if (--_stack_depth < 0) + failure(underfull_stack); + if (valid_upto(gr_slatMax, bc[0])) + valid_upto(_max.attrid[bc[0]], bc[1]); + test_context(); + break; + case PUSH_SLOT_ATTR : + ++_stack_depth; + valid_upto(gr_slatMax, bc[0]); + valid_upto(_rule_length, _pre_context + int8(bc[1])); ++ if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes ++ failure(out_of_range_data); + break; + case PUSH_GLYPH_ATTR_OBS : + ++_stack_depth; + valid_upto(_max.glyf_attrs, bc[0]); + valid_upto(_rule_length, _pre_context + int8(bc[1])); + break; + case PUSH_GLYPH_METRIC : + ++_stack_depth; +@@ -656,24 +661,24 @@ bool Machine::Code::decoder::validate_op + return false; + } + return true; + } + + + bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw() + { +- const bool t = x < limit; ++ const bool t = (limit != 0) && (x < limit); + if (!t) failure(out_of_range_data); + return t; + } + + bool Machine::Code::decoder::test_context() const throw() + { +- if (_pre_context >= _rule_length) ++ if (_pre_context >= _rule_length || _analysis.slotref >= analysis::NUMCONTEXTS - 1) + { + failure(out_of_range_data); + return false; + } + return true; + } + + inline +@@ -681,34 +686,34 @@ void Machine::Code::failure(const status + release_buffers(); + _status = s; + } + + + inline + void Machine::Code::decoder::analysis::set_ref(int index, bool incinsert) throw() { + if (incinsert && contexts[slotref].flags.inserted) --index; +- if (index + slotref < 0) return; ++ if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return; + contexts[index + slotref].flags.referenced = true; + if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref; + } + + + inline + void Machine::Code::decoder::analysis::set_noref(int index) throw() { + if (contexts[slotref].flags.inserted) --index; +- if (index + slotref < 0) return; ++ if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return; + if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref; + } + + + inline + void Machine::Code::decoder::analysis::set_changed(int index) throw() { + if (contexts[slotref].flags.inserted) --index; +- if (index + slotref < 0) return; ++ if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return; + contexts[index + slotref].flags.changed = true; + if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref; + } + + + void Machine::Code::release_buffers() throw() + { + if (_own) +diff --git a/gfx/graphite2/src/GlyphCache.cpp b/gfx/graphite2/src/GlyphCache.cpp +--- a/gfx/graphite2/src/GlyphCache.cpp ++++ b/gfx/graphite2/src/GlyphCache.cpp +@@ -260,17 +260,17 @@ GlyphCache::Loader::Loader(const Face & + _head = Face::Table(); + return; + } + + if (!dumb_font) + { + if ((m_pGlat = Face::Table(face, Tag::Glat, 0x00030000)) == NULL + || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL +- || m_pGloc.size() < 6) ++ || m_pGloc.size() < 8) + { + _head = Face::Table(); + return; + } + const byte * p = m_pGloc; + int version = be::read(p); + const uint16 flags = be::read(p); + _num_attrs = be::read(p); +diff --git a/gfx/graphite2/src/Pass.cpp b/gfx/graphite2/src/Pass.cpp +--- a/gfx/graphite2/src/Pass.cpp ++++ b/gfx/graphite2/src/Pass.cpp +@@ -233,17 +233,17 @@ bool Pass::readRules(const byte * rule_m + m_codes = new Code [m_numRules*2]; + const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data); + m_progs = gralloc(prog_pool_sz); + byte * prog_pool_free = m_progs, + * prog_pool_end = m_progs + prog_pool_sz; + if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e); + + Rule * r = m_rules + m_numRules - 1; +- for (size_t n = m_numRules; n; --n, --r, ac_end = ac_begin, rc_end = rc_begin) ++ for (size_t n = m_numRules; r >= m_rules; --n, --r, ac_end = ac_begin, rc_end = rc_begin) + { + face.error_context((face.error_context() & 0xFFFF00) + EC_ARULE + ((n - 1) << 24)); + r->preContext = *--precontext; + r->sort = be::peek(--sort_key); + #ifndef NDEBUG + r->rule_idx = n - 1; + #endif + if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt) +@@ -405,16 +405,17 @@ bool Pass::runGraphite(vm::Machine & m, + json::closer rules_array_closer(fsm.dbgout); + #endif + + m.slotMap().highwater(currHigh); + int lc = m_iMaxLoop; + do + { + findNDoRule(s, m, fsm); ++ if (m.status() != Machine::finished) return false; + if (s && (s == m.slotMap().highwater() || m.slotMap().highpassed() || --lc == 0)) { + if (!lc) + s = m.slotMap().highwater(); + lc = m_iMaxLoop; + if (s) + m.slotMap().highwater(s->next()); + } + } while (s); +@@ -495,17 +496,22 @@ void Pass::findNDoRule(Slot * & slot, Ma + { + assert(slot); + + if (runFSM(fsm, slot)) + { + // Search for the first rule which passes the constraint + const RuleEntry * r = fsm.rules.begin(), + * const re = fsm.rules.end(); +- while (r != re && !testConstraint(*r->rule, m)) ++r; ++ while (r != re && !testConstraint(*r->rule, m)) ++ { ++ ++r; ++ if (m.status() != Machine::finished) ++ return; ++ } + + #if !defined GRAPHITE2_NTRACING + if (fsm.dbgout) + { + if (fsm.rules.size() != 0) + { + *fsm.dbgout << json::item << json::object; + dumpRuleEventConsidered(fsm, *r); +@@ -530,16 +536,17 @@ void Pass::findNDoRule(Slot * & slot, Ma + } + } + else + #endif + { + if (r != re) + { + const int adv = doAction(r->rule->action, slot, m); ++ if (m.status() != Machine::finished) return; + if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot); + adjustSlot(adv, slot, fsm.slots); + return; + } + } + } + + slot = slot->next(); +diff --git a/gfx/graphite2/src/Segment.cpp b/gfx/graphite2/src/Segment.cpp +--- a/gfx/graphite2/src/Segment.cpp ++++ b/gfx/graphite2/src/Segment.cpp +@@ -205,18 +205,23 @@ Slot *Segment::newSlot() + void Segment::freeSlot(Slot *aSlot) + { + if (m_last == aSlot) m_last = aSlot->prev(); + if (m_first == aSlot) m_first = aSlot->next(); + if (aSlot->attachedTo()) + aSlot->attachedTo()->removeChild(aSlot); + while (aSlot->firstChild()) + { +- aSlot->firstChild()->attachTo(NULL); +- aSlot->removeChild(aSlot->firstChild()); ++ if (aSlot->firstChild()->attachedTo() == aSlot) ++ { ++ aSlot->firstChild()->attachTo(NULL); ++ aSlot->removeChild(aSlot->firstChild()); ++ } ++ else ++ aSlot->firstChild(NULL); + } + // reset the slot incase it is reused + ::new (aSlot) Slot(aSlot->userAttrs()); + memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16)); + // Update generation counter for debug + #if !defined GRAPHITE2_NTRACING + if (m_face->logger()) + ++aSlot->userAttrs()[m_silf->numUser()]; +diff --git a/gfx/graphite2/src/Slot.cpp b/gfx/graphite2/src/Slot.cpp +--- a/gfx/graphite2/src/Slot.cpp ++++ b/gfx/graphite2/src/Slot.cpp +@@ -192,16 +192,18 @@ int32 Slot::clusterMetric(const Segment + #define SLOTGETCOLATTR(x) { SlotCollision *c = seg->collisionInfo(this); return c ? int(c-> x) : 0; } + + int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const + { + if (ind == gr_slatUserDefnV1) + { + ind = gr_slatUserDefn; + subindex = 0; ++ if (seg->numAttrs() == 0) ++ return 0; + } + else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth) + { + int indx = ind - gr_slatJStretch; + return getJustify(seg, indx / 5, indx % 5); + } + + switch (ind) +@@ -269,16 +271,18 @@ int Slot::getAttr(const Segment *seg, at + break; } + + void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map) + { + if (ind == gr_slatUserDefnV1) + { + ind = gr_slatUserDefn; + subindex = 0; ++ if (seg->numAttrs() == 0) ++ return; + } + else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth) + { + int indx = ind - gr_slatJStretch; + return setJustify(seg, indx / 5, indx % 5, value); + } + + switch (ind) +@@ -416,32 +420,32 @@ bool Slot::sibling(Slot *ap) + } + + bool Slot::removeChild(Slot *ap) + { + if (this == ap || !m_child) return false; + else if (ap == m_child) + { + Slot *nSibling = m_child->nextSibling(); +- m_child->sibling(NULL); ++ m_child->removeSibling(nSibling); + m_child = nSibling; + return true; + } + else + return m_child->removeSibling(ap); + return true; + } + + bool Slot::removeSibling(Slot *ap) + { + if (this == ap || !m_sibling) return false; + else if (ap == m_sibling) + { + m_sibling = m_sibling->nextSibling(); +- ap->sibling(NULL); ++ if (m_sibling) ap->removeSibling(m_sibling); + return true; + } + else + return m_sibling->removeSibling(ap); + return true; + } + + void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph) +diff --git a/gfx/graphite2/src/TtfUtil.cpp b/gfx/graphite2/src/TtfUtil.cpp +--- a/gfx/graphite2/src/TtfUtil.cpp ++++ b/gfx/graphite2/src/TtfUtil.cpp +@@ -884,18 +884,19 @@ const void * FindCmapSubtable(const void + } + + return 0; + } + + /*---------------------------------------------------------------------------------------------- + Check the Microsoft Unicode subtable for expected values + ----------------------------------------------------------------------------------------------*/ +-bool CheckCmapSubtable4(const void * pCmapSubtable4, size_t table_len /*, unsigned int maxgid*/) ++bool CheckCmapSubtable4(const void * pCmapSubtable4, const void * pCmapEnd /*, unsigned int maxgid*/) + { ++ size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable4; + if (!pCmapSubtable4) return false; + const Sfnt::CmapSubTable * pTable = reinterpret_cast(pCmapSubtable4); + // Bob H say some freeware TT fonts have version 1 (eg, CALIGULA.TTF) + // so don't check subtable version. 21 Mar 2002 spec changes version to language. + if (be::swap(pTable->format) != 4) return false; + const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast(pCmapSubtable4); + uint16 length = be::swap(pTable4->length); + if (length > table_len) +@@ -1044,17 +1045,17 @@ unsigned int CmapSubtable4NextCodepoint( + *pRangeKey = nRange - 1; + return 0xFFFF; + } + + int iRange = (pRangeKey) ? *pRangeKey : 0; + // Just in case we have a bad key: + while (iRange > 0 && be::peek(pStartCode + iRange) > nUnicodePrev) + iRange--; +- while (be::peek(pTable->end_code + iRange) < nUnicodePrev) ++ while (iRange < nRange - 1 && be::peek(pTable->end_code + iRange) < nUnicodePrev) + iRange++; + + // Now iRange is the range containing nUnicodePrev. + unsigned int nStartCode = be::peek(pStartCode + iRange); + unsigned int nEndCode = be::peek(pTable->end_code + iRange); + + if (nStartCode > nUnicodePrev) + // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable +@@ -1069,36 +1070,37 @@ unsigned int CmapSubtable4NextCodepoint( + return nUnicodePrev + 1; + } + + // Otherwise the next codepoint is the first one in the next range. + // There is guaranteed to be a next range because there must be one that + // ends with 0xFFFF. + if (pRangeKey) + *pRangeKey = iRange + 1; +- return be::peek(pStartCode + iRange + 1); ++ return (iRange + 1 >= nRange) ? 0xFFFF : be::peek(pStartCode + iRange + 1); + } + + /*---------------------------------------------------------------------------------------------- + Check the Microsoft UCS-4 subtable for expected values. + ----------------------------------------------------------------------------------------------*/ +-bool CheckCmapSubtable12(const void *pCmapSubtable12, size_t table_len /*, unsigned int maxgid*/) ++bool CheckCmapSubtable12(const void *pCmapSubtable12, const void *pCmapEnd /*, unsigned int maxgid*/) + { ++ size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable12; + if (!pCmapSubtable12) return false; + const Sfnt::CmapSubTable * pTable = reinterpret_cast(pCmapSubtable12); + if (be::swap(pTable->format) != 12) + return false; + const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast(pCmapSubtable12); + uint32 length = be::swap(pTable12->length); + if (length > table_len) + return false; + if (length < sizeof(Sfnt::CmapSubTableFormat12)) + return false; + uint32 num_groups = be::swap(pTable12->num_groups); +- if (length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3)) ++ if (num_groups > 0x10000000 || length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3)) + return false; + #if 0 + for (unsigned int i = 0; i < num_groups; ++i) + { + if (be::swap(pTable12->group[i].end_char_code) - be::swap(pTable12->group[i].start_char_code) + be::swap(pTable12->group[i].start_glyph_id) > maxgid) + return false; + if (i > 0 && be::swap(pTable12->group[i].start_char_code) <= be::swap(pTable12->group[i-1].end_char_code)) + return false; +@@ -1161,17 +1163,17 @@ unsigned int CmapSubtable12NextCodepoint + *pRangeKey = nRange; + return 0x10FFFF; + } + + int iRange = (pRangeKey) ? *pRangeKey : 0; + // Just in case we have a bad key: + while (iRange > 0 && be::swap(pTable->group[iRange].start_char_code) > nUnicodePrev) + iRange--; +- while (be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev) ++ while (iRange < nRange - 1 && be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev) + iRange++; + + // Now iRange is the range containing nUnicodePrev. + + unsigned int nStartCode = be::swap(pTable->group[iRange].start_char_code); + unsigned int nEndCode = be::swap(pTable->group[iRange].end_char_code); + + if (nStartCode > nUnicodePrev) +diff --git a/gfx/graphite2/src/call_machine.cpp b/gfx/graphite2/src/call_machine.cpp +--- a/gfx/graphite2/src/call_machine.cpp ++++ b/gfx/graphite2/src/call_machine.cpp +@@ -67,32 +67,34 @@ using namespace vm; + struct regbank { + slotref is; + slotref * map; + SlotMap & smap; + slotref * const map_base; + const instr * & ip; + uint8 direction; + int8 flags; ++ Machine::status_t & status; + }; + + typedef bool (* ip_t)(registers); + + // Pull in the opcode definitions + // We pull these into a private namespace so these otherwise common names dont + // pollute the toplevel namespace. + namespace { + #define smap reg.smap + #define seg smap.segment + #define is reg.is + #define ip reg.ip + #define map reg.map + #define mapb reg.map_base + #define flags reg.flags + #define dir reg.direction ++#define status reg.status + + #include "inc/opcodes.h" + + #undef smap + #undef seg + #undef is + #undef ip + #undef map +@@ -108,17 +110,17 @@ Machine::stack_t Machine::run(const ins + { + assert(program != 0); + + // Declare virtual machine registers + const instr * ip = program-1; + const byte * dp = data; + stack_t * sp = _stack + Machine::STACK_GUARD, + * const sb = sp; +- regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0}; ++ regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0, _status}; + + // Run the program + while ((reinterpret_cast(*++ip))(dp, sp, sb, reg)) {} + const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0; + + check_final_stack(sp); + map = reg.map; + *map = reg.is; +diff --git a/gfx/graphite2/src/direct_machine.cpp b/gfx/graphite2/src/direct_machine.cpp +--- a/gfx/graphite2/src/direct_machine.cpp ++++ b/gfx/graphite2/src/direct_machine.cpp +@@ -57,36 +57,37 @@ using namespace vm; + namespace { + + const void * direct_run(const bool get_table_mode, + const instr * program, + const byte * data, + Machine::stack_t * stack, + slotref * & __map, + uint8 _dir, ++ Machine::status_t & status, + SlotMap * __smap=0) + { + // We need to define and return to opcode table from within this function + // other inorder to take the addresses of the instruction bodies. + #include "inc/opcode_table.h" + if (get_table_mode) + return opcode_table; + + // Declare virtual machine registers +- const instr * ip = program; +- const byte * dp = data; +- Machine::stack_t * sp = stack + Machine::STACK_GUARD, +- * const sb = sp; +- SlotMap & smap = *__smap; +- Segment & seg = smap.segment; +- slotref is = *__map, +- * map = __map, +- * const mapb = smap.begin()+smap.context(); +- uint8 dir = _dir; +- int8 flags = 0; ++ const instr * ip = program; ++ const byte * dp = data; ++ Machine::stack_t * sp = stack + Machine::STACK_GUARD, ++ * const sb = sp; ++ SlotMap & smap = *__smap; ++ Segment & seg = smap.segment; ++ slotref is = *__map, ++ * map = __map, ++ * const mapb = smap.begin()+smap.context(); ++ uint8 dir = _dir; ++ int8 flags = 0; + + // start the program + goto **ip; + + // Pull in the opcode definitions + #include "inc/opcodes.h" + + end: +@@ -95,25 +96,26 @@ const void * direct_run(const bool + return sp; + } + + } + + const opcode_t * Machine::getOpcodeTable() throw() + { + slotref * dummy; +- return static_cast(direct_run(true, 0, 0, 0, dummy, 0)); ++ Machine::status_t dumstat = Machine::finished; ++ return static_cast(direct_run(true, 0, 0, 0, dummy, 0, dumstat)); + } + + + Machine::stack_t Machine::run(const instr * program, + const byte * data, + slotref * & is) + { + assert(program != 0); + + const stack_t *sp = static_cast( +- direct_run(false, program, data, _stack, is, _map.dir(), &_map)); ++ direct_run(false, program, data, _stack, is, _map.dir(), _status, &_map)); + const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0; + check_final_stack(sp); + return ret; + } + +diff --git a/gfx/graphite2/src/inc/Code.h b/gfx/graphite2/src/inc/Code.h +--- a/gfx/graphite2/src/inc/Code.h ++++ b/gfx/graphite2/src/inc/Code.h +@@ -109,17 +109,17 @@ public: + int32 run(Machine &m, slotref * & map) const; + + CLASS_NEW_DELETE; + }; + + inline + size_t Machine::Code::estimateCodeDataOut(size_t n_bc) + { +- return n_bc * (sizeof(instr)+sizeof(byte)); ++ return (n_bc + 1) * (sizeof(instr)+sizeof(byte)); + } + + + inline Machine::Code::Code() throw() + : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), + _status(loaded), _constraint(false), _modify(false), _delete(false), + _own(false) + { +diff --git a/gfx/graphite2/src/inc/Machine.h b/gfx/graphite2/src/inc/Machine.h +--- a/gfx/graphite2/src/inc/Machine.h ++++ b/gfx/graphite2/src/inc/Machine.h +@@ -135,17 +135,18 @@ public: + + class Code; + + enum status_t { + finished = 0, + stack_underflow, + stack_not_empty, + stack_overflow, +- slot_offset_out_bounds ++ slot_offset_out_bounds, ++ died_early + }; + + Machine(SlotMap &) throw(); + static const opcode_t * getOpcodeTable() throw(); + + CLASS_NEW_DELETE; + + SlotMap & slotMap() const throw(); +diff --git a/gfx/graphite2/src/inc/TtfUtil.h b/gfx/graphite2/src/inc/TtfUtil.h +--- a/gfx/graphite2/src/inc/TtfUtil.h ++++ b/gfx/graphite2/src/inc/TtfUtil.h +@@ -132,21 +132,21 @@ public: + int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId, + int *nameIdList, int cNameIds, short *langIdList); + void SwapWString(void * pWStr, size_t nSize = 0); // throw (std::invalid_argument); + #endif + + ////////////////////////////////// cmap lookup tools + const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3, + int nEncodingId = 1, size_t length = 0); +- bool CheckCmapSubtable4(const void * pCmap31, size_t table_len /*, unsigned int maxgid*/); ++ bool CheckCmapSubtable4(const void * pCmap31, const void * pCmapEnd /*, unsigned int maxgid*/); + gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey = 0); + unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId, + int * pRangeKey = 0); +- bool CheckCmapSubtable12(const void *pCmap310, size_t table_len /*, unsigned int maxgid*/); ++ bool CheckCmapSubtable12(const void *pCmap310, const void * pCmapEnd /*, unsigned int maxgid*/); + gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0); + unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId, + int * pRangeKey = 0); + + ///////////////////////////////// horizontal metric data for a glyph + bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, + const void * pHhea, int & nLsb, unsigned int & nAdvWid); + +diff --git a/gfx/graphite2/src/inc/opcodes.h b/gfx/graphite2/src/inc/opcodes.h +--- a/gfx/graphite2/src/inc/opcodes.h ++++ b/gfx/graphite2/src/inc/opcodes.h +@@ -71,17 +71,17 @@ of the License or (at your option) any l + #define use_params(n) dp += n + + #define declare_params(n) const byte * param = dp; \ + use_params(n); + + #define push(n) { *++sp = n; } + #define pop() (*sp--) + #define slotat(x) (map[(x)]) +-#define DIE { is=seg.last(); EXIT(1); } ++#define DIE { is=seg.last(); status = Machine::died_early; EXIT(1); } + #define POSITIONED 1 + + STARTOP(nop) + do {} while (0); + ENDOP + + STARTOP(push_byte) + declare_params(1); +@@ -387,30 +387,30 @@ STARTOP(attr_set) + ENDOP + + STARTOP(attr_add) + declare_params(1); + const attrCode slat = attrCode(uint8(*param)); + const int val = int(pop()); + if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) + { +- seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); ++ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); + flags |= POSITIONED; + } + int res = is->getAttr(&seg, slat, 0); + is->setAttr(&seg, slat, 0, val + res, smap); + ENDOP + + STARTOP(attr_sub) + declare_params(1); + const attrCode slat = attrCode(uint8(*param)); + const int val = int(pop()); + if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) + { +- seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); ++ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); + flags |= POSITIONED; + } + int res = is->getAttr(&seg, slat, 0); + is->setAttr(&seg, slat, 0, res - val, smap); + ENDOP + + STARTOP(attr_set_slot) + declare_params(1); +@@ -429,17 +429,17 @@ STARTOP(iattr_set_slot) + ENDOP + + STARTOP(push_slot_attr) + declare_params(2); + const attrCode slat = attrCode(uint8(param[0])); + const int slot_ref = int8(param[1]); + if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) + { +- seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); ++ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); + flags |= POSITIONED; + } + slotref slot = slotat(slot_ref); + if (slot) + { + int res = slot->getAttr(&seg, slat, 0); + push(res); + } +@@ -505,17 +505,17 @@ ENDOP + + STARTOP(push_islot_attr) + declare_params(3); + const attrCode slat = attrCode(uint8(param[0])); + const int slot_ref = int8(param[1]), + idx = uint8(param[2]); + if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) + { +- seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); ++ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); + flags |= POSITIONED; + } + slotref slot = slotat(slot_ref); + if (slot) + { + int res = slot->getAttr(&seg, slat, idx); + push(res); + } +