[subset] Fixed out of bounds read when subsetting hdmx.
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index f08fe39..8df9957 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -43,12 +43,15 @@
   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 @@
       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 @@
     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 @@
     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<DeviceRecord> ()->serialize (c, subset_view);
+      if (!c->start_embed<DeviceRecord> ()->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 0000000..1af243e
--- /dev/null
+++ b/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a
Binary files differ
diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c
index 609ee06..dd20b2a 100644
--- a/test/api/test-subset-hdmx.c
+++ b/test/api/test-subset-hdmx.c
@@ -51,6 +51,28 @@
 }
 
 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)
 {
   hb_face_t *face_abc = hb_subset_test_open_font("fonts/Roboto-Regular.abc.ttf");
@@ -75,6 +97,7 @@
   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();