diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index f08fe39d8bed651dc1df1333bbee4cc220ab5209..8df99576d038750b816b56751a42ccea7de8d1c2 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -43,12 +43,15 @@ struct DeviceRecord struct SubsetView { const DeviceRecord *source_device_record; + unsigned int size_device_record; hb_subset_plan_t *subset_plan; inline void init(const DeviceRecord *source_device_record, + unsigned int size_device_record, hb_subset_plan_t *subset_plan) { this->source_device_record = source_device_record; + this->size_device_record = size_device_record; this->subset_plan = subset_plan; } @@ -57,11 +60,17 @@ struct DeviceRecord return this->subset_plan->gids_to_retain_sorted.len; } - inline const HBUINT8& operator [] (unsigned int i) const + inline const HBUINT8* operator [] (unsigned int i) const { - if (unlikely (i >= len())) return Null(HBUINT8); + if (unlikely (i >= len())) return nullptr; hb_codepoint_t gid = this->subset_plan->gids_to_retain_sorted [i]; - return this->source_device_record->widths[gid]; + + const HBUINT8* width = &(this->source_device_record->widths[gid]); + + if (width < ((const HBUINT8 *) this->source_device_record) + size_device_record) + return width; + else + return nullptr; } }; @@ -85,7 +94,15 @@ struct DeviceRecord this->max_width.set (subset_view.source_device_record->max_width); for (unsigned int i = 0; i < subset_view.len(); i++) - widths[i].set (subset_view[i]); + { + const HBUINT8 *width = subset_view[i]; + if (!width) + { + DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i); + return_trace (false); + } + widths[i].set (*width); + } return_trace (true); } @@ -133,9 +150,10 @@ struct hdmx for (unsigned int i = 0; i < source_hdmx->num_records; i++) { DeviceRecord::SubsetView subset_view; - subset_view.init (&(*source_hdmx)[i], plan); + subset_view.init (&(*source_hdmx)[i], source_hdmx->size_device_record, plan); - c->start_embed ()->serialize (c, subset_view); + if (!c->start_embed ()->serialize (c, subset_view)) + return_trace (false); } return_trace (true); diff --git a/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a b/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a new file mode 100644 index 0000000000000000000000000000000000000000..1af243ebcb7cfe23b21e47fc1732c84e4ddd541e Binary files /dev/null and b/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a differ diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c index 609ee061f786f33a51464a18eb39c6d46c20c74e..dd20b2a2b98b2ed67e8da4ccf3c569fef101c1a6 100644 --- a/test/api/test-subset-hdmx.c +++ b/test/api/test-subset-hdmx.c @@ -50,6 +50,28 @@ test_subset_hdmx_simple_subset (void) hb_face_destroy (face_ac); } +static void +test_subset_hdmx_invalid (void) +{ + hb_face_t *face = hb_subset_test_open_font("fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a"); + + hb_subset_input_t *input = hb_subset_input_create_or_fail (); + hb_set_t *codepoints = hb_subset_input_unicode_set (input); + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'b'); + hb_set_add (codepoints, 'c'); + + hb_subset_profile_t *profile = hb_subset_profile_create(); + hb_face_t *subset = hb_subset (face, profile, input); + g_assert (subset); + g_assert (subset == hb_face_get_empty ()); + + hb_subset_input_destroy (input); + hb_subset_profile_destroy (profile); + hb_face_destroy (subset); + hb_face_destroy (face); +} + static void test_subset_hdmx_noop (void) { @@ -75,6 +97,7 @@ main (int argc, char **argv) hb_test_init (&argc, &argv); hb_test_add (test_subset_hdmx_simple_subset); + hb_test_add (test_subset_hdmx_invalid); hb_test_add (test_subset_hdmx_noop); return hb_test_run();