[subset] handle cmap4 overflows.
If a cmap4 subtable overflows during serialization drop it and the corresponding EncodingRecord. Don't drop the corresponding cmap12 table if it would have otherwise been removed.
This commit is contained in:
parent
bf81bbfb35
commit
2bd911b8b4
|
@ -277,9 +277,17 @@ struct CmapSubtableFormat4
|
||||||
HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
|
HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
|
||||||
if (unlikely (!c->check_success (idRangeOffset))) return;
|
if (unlikely (!c->check_success (idRangeOffset))) return;
|
||||||
|
|
||||||
if (unlikely (!c->check_assign(this->length,
|
this->length = c->length () - table_initpos;
|
||||||
c->length () - table_initpos,
|
if ((long long) this->length != (long long) c->length () - table_initpos)
|
||||||
HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
|
{
|
||||||
|
// Length overflowed. Discard the current object before setting the error condition, otherwise
|
||||||
|
// discard is a noop which prevents the higher level code from reverting the serializer to the
|
||||||
|
// pre-error state in cmap4 overflow handling code.
|
||||||
|
c->pop_discard ();
|
||||||
|
c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this->segCountX2 = segcount * 2;
|
this->segCountX2 = segcount * 2;
|
||||||
this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
|
this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
|
||||||
this->searchRange = 2 * (1u << this->entrySelector);
|
this->searchRange = 2 * (1u << this->entrySelector);
|
||||||
|
@ -1384,26 +1392,45 @@ struct cmap
|
||||||
|
|
||||||
template<typename Iterator, typename EncodingRecIter,
|
template<typename Iterator, typename EncodingRecIter,
|
||||||
hb_requires (hb_is_iterator (EncodingRecIter))>
|
hb_requires (hb_is_iterator (EncodingRecIter))>
|
||||||
void serialize (hb_serialize_context_t *c,
|
bool serialize (hb_serialize_context_t *c,
|
||||||
Iterator it,
|
Iterator it,
|
||||||
EncodingRecIter encodingrec_iter,
|
EncodingRecIter encodingrec_iter,
|
||||||
const void *base,
|
const void *base,
|
||||||
const hb_subset_plan_t *plan)
|
const hb_subset_plan_t *plan,
|
||||||
|
bool drop_format_4 = false)
|
||||||
{
|
{
|
||||||
if (unlikely (!c->extend_min ((*this)))) return;
|
if (unlikely (!c->extend_min ((*this)))) return false;
|
||||||
this->version = 0;
|
this->version = 0;
|
||||||
|
|
||||||
unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
|
unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
|
||||||
|
auto snap = c->snapshot ();
|
||||||
|
|
||||||
for (const EncodingRecord& _ : encodingrec_iter)
|
for (const EncodingRecord& _ : encodingrec_iter)
|
||||||
{
|
{
|
||||||
|
if (c->in_error ())
|
||||||
|
return false;
|
||||||
|
|
||||||
unsigned format = (base+_.subtable).u.format;
|
unsigned format = (base+_.subtable).u.format;
|
||||||
if (format != 4 && format != 12 && format != 14) continue;
|
if (format != 4 && format != 12 && format != 14) continue;
|
||||||
|
|
||||||
hb_set_t unicodes_set;
|
hb_set_t unicodes_set;
|
||||||
(base+_.subtable).collect_unicodes (&unicodes_set);
|
(base+_.subtable).collect_unicodes (&unicodes_set);
|
||||||
|
|
||||||
if (format == 4) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
|
if (!drop_format_4 && format == 4)
|
||||||
|
{
|
||||||
|
c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
|
||||||
|
if (c->in_error () && c->only_overflow ())
|
||||||
|
{
|
||||||
|
// cmap4 overflowed, reset and retry serialization without format 4 subtables.
|
||||||
|
c->revert (snap);
|
||||||
|
return serialize (c, it,
|
||||||
|
encodingrec_iter,
|
||||||
|
base,
|
||||||
|
plan,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (format == 12)
|
else if (format == 12)
|
||||||
{
|
{
|
||||||
if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue;
|
if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue;
|
||||||
|
@ -1411,10 +1438,12 @@ struct cmap
|
||||||
}
|
}
|
||||||
else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
|
else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
|
||||||
}
|
}
|
||||||
|
|
||||||
c->check_assign(this->encodingRecord.len,
|
c->check_assign(this->encodingRecord.len,
|
||||||
(c->length () - cmap::min_size)/EncodingRecord::static_size,
|
(c->length () - cmap::min_size)/EncodingRecord::static_size,
|
||||||
HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
||||||
|
|
||||||
|
// Fail if format 4 was dropped and there is no cmap12.
|
||||||
|
return !drop_format_4 || format12objidx;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Iterator, typename EncodingRecordIterator,
|
template<typename Iterator, typename EncodingRecordIterator,
|
||||||
|
@ -1535,8 +1564,8 @@ struct cmap
|
||||||
| hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
|
| hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
|
||||||
{ return (_.second != HB_MAP_VALUE_INVALID); })
|
{ return (_.second != HB_MAP_VALUE_INVALID); })
|
||||||
;
|
;
|
||||||
cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan);
|
|
||||||
return_trace (true);
|
return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
|
||||||
}
|
}
|
||||||
|
|
||||||
const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
|
const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
|
||||||
|
|
|
@ -102,10 +102,11 @@ struct hb_serialize_context_t
|
||||||
char *tail;
|
char *tail;
|
||||||
object_t *current; // Just for sanity check
|
object_t *current; // Just for sanity check
|
||||||
unsigned num_links;
|
unsigned num_links;
|
||||||
|
hb_serialize_error_t errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
snapshot_t snapshot ()
|
snapshot_t snapshot ()
|
||||||
{ return snapshot_t { head, tail, current, current->links.length }; }
|
{ return snapshot_t { head, tail, current, current->links.length, errors }; }
|
||||||
|
|
||||||
hb_serialize_context_t (void *start_, unsigned int size) :
|
hb_serialize_context_t (void *start_, unsigned int size) :
|
||||||
start ((char *) start_),
|
start ((char *) start_),
|
||||||
|
@ -136,6 +137,12 @@ struct hb_serialize_context_t
|
||||||
HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; }
|
HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; }
|
||||||
HB_NODISCARD bool offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
|
HB_NODISCARD bool offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
|
||||||
HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
|
HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
|
||||||
|
HB_NODISCARD bool only_overflow () const
|
||||||
|
{
|
||||||
|
return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW
|
||||||
|
|| errors == HB_SERIALIZE_ERROR_INT_OVERFLOW
|
||||||
|
|| errors == HB_SERIALIZE_ERROR_ARRAY_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
void reset (void *start_, unsigned int size)
|
void reset (void *start_, unsigned int size)
|
||||||
{
|
{
|
||||||
|
@ -317,9 +324,11 @@ struct hb_serialize_context_t
|
||||||
|
|
||||||
void revert (snapshot_t snap)
|
void revert (snapshot_t snap)
|
||||||
{
|
{
|
||||||
if (unlikely (in_error ())) return;
|
// Overflows that happened after the snapshot will be erased by the revert.
|
||||||
|
if (unlikely (in_error () && !only_overflow ())) return;
|
||||||
assert (snap.current == current);
|
assert (snap.current == current);
|
||||||
current->links.shrink (snap.num_links);
|
current->links.shrink (snap.num_links);
|
||||||
|
errors = snap.errors;
|
||||||
revert (snap.head, snap.tail);
|
revert (snap.head, snap.tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,6 +372,8 @@ struct hb_serialize_context_t
|
||||||
assert (current->head <= (const char *) &ofs);
|
assert (current->head <= (const char *) &ofs);
|
||||||
|
|
||||||
auto& link = *current->links.push ();
|
auto& link = *current->links.push ();
|
||||||
|
if (current->links.in_error ())
|
||||||
|
err (HB_SERIALIZE_ERROR_OTHER);
|
||||||
|
|
||||||
link.width = sizeof (T);
|
link.width = sizeof (T);
|
||||||
link.is_signed = hb_is_signed (hb_unwrap_type (T));
|
link.is_signed = hb_is_signed (hb_unwrap_type (T));
|
||||||
|
|
Loading…
Reference in New Issue