[repacker] begin implementing a fuzzer for the repacker api.
diff --git a/src/graph/graph.hh b/src/graph/graph.hh
index c6f0884..20d6463 100644
--- a/src/graph/graph.hh
+++ b/src/graph/graph.hh
@@ -941,6 +941,18 @@
     return made_change;
   }
 
+  bool is_fully_connected ()
+  {
+    update_parents();
+
+    for (unsigned i = 0; i < root_idx (); i++)
+    {
+      if (!vertices_[i].parents)
+        return false;
+    }
+    return true;
+  }
+
   void print_orphaned_nodes ()
   {
     if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh
index 70f1d0e..ba30557 100644
--- a/src/hb-repacker.hh
+++ b/src/hb-repacker.hh
@@ -376,6 +376,12 @@
                       unsigned max_rounds = 20,
                       bool recalculate_extensions = false) {
   graph_t sorted_graph (packed);
+  if (!sorted_graph.is_fully_connected ())
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Input graph is not fully connected.");
+    return nullptr;
+  }
+
   if (!hb_resolve_graph_overflows (table_tag, max_rounds, recalculate_extensions, sorted_graph))
     return nullptr;
 
diff --git a/test/fuzzing/hb-repacker-fuzzer.cc b/test/fuzzing/hb-repacker-fuzzer.cc
new file mode 100644
index 0000000..67ba065
--- /dev/null
+++ b/test/fuzzing/hb-repacker-fuzzer.cc
@@ -0,0 +1,134 @@
+#include "hb-fuzzer.hh"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "hb-subset-repacker.h"
+
+typedef struct
+{
+  uint16_t parent;
+  uint16_t delta;
+  uint16_t position;
+  uint8_t width;
+} link_t;
+
+template <typename T>
+bool read(const uint8_t** data, size_t* size, T* out)
+{
+  if (*size < sizeof (T)) return false;
+
+  *out = * ((T*) *data);
+
+  *data += sizeof (T);
+  *size -= sizeof (T);
+
+  return true;
+}
+
+void cleanup (hb_object_t* objects, uint16_t num_objects)
+{
+  for (uint32_t i = 0; i < num_objects; i++)
+    free (objects[i].real_links);
+}
+
+void add_links_to_objects (hb_object_t* objects, uint16_t num_objects,
+                           link_t* links, uint16_t num_links)
+{
+  unsigned* link_count = (unsigned*) calloc (num_objects, sizeof (unsigned));
+
+  for (uint32_t i = 0; i < num_links; i++)
+  {
+    uint16_t parent_idx = links[i].parent;
+    link_count[parent_idx]++;
+  }
+
+  for (uint32_t i = 0; i < num_objects; i++)
+  {
+    objects[i].num_real_links = link_count[i];
+    objects[i].real_links = (hb_link_t*) calloc (link_count[i], sizeof (hb_link_t));
+    objects[i].num_virtual_links = 0;
+    objects[i].virtual_links = nullptr;
+  }
+
+  for (uint32_t i = 0; i < num_links; i++)
+  {
+    uint16_t parent_idx = links[i].parent;
+    uint16_t child_idx = links[i].parent + links[i].delta + 1;
+    hb_link_t* link = &(objects[parent_idx].real_links[link_count[parent_idx] - 1]);
+
+    link->width = links[i].width;
+    link->position = links[i].position;
+    link->objidx = child_idx;
+    link_count[parent_idx]--;
+  }
+
+  bool* reachable = (bool*) calloc (num_objects, sizeof (bool));
+
+
+
+  free (reachable);
+  free (link_count);
+}
+
+extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
+{
+  alloc_state = _fuzzing_alloc_state (data, size);
+
+  uint16_t num_objects = 0;
+  hb_object_t* objects = nullptr;
+
+  uint16_t num_real_links = 0;
+  link_t* links = nullptr;
+
+  hb_tag_t table_tag;
+  if (!read<hb_tag_t> (&data, &size, &table_tag)) goto end;
+  if (!read<uint16_t> (&data, &size, &num_objects)) goto end;
+
+  objects = (hb_object_t*) calloc (num_objects, sizeof (hb_object_t));
+  for (uint32_t i = 0; i < num_objects; i++)
+  {
+    uint16_t blob_size;
+    if (!read<uint16_t> (&data, &size, &blob_size)) goto end;
+    if (size < blob_size) goto end;
+
+    objects[i].head = (char*) data;
+    objects[i].tail = (char*) (data + blob_size);
+
+    size -= blob_size;
+    data += blob_size;
+  }
+
+  if (!read<uint16_t> (&data, &size, &num_real_links)) goto end;
+  links = (link_t*) calloc (num_real_links, sizeof (link_t));
+  for (uint32_t i = 0; i < num_real_links; i++)
+  {
+    if (!read<link_t> (&data, &size, &links[i])) goto end;
+
+    uint32_t child_idx = ((uint32_t) links[i].parent) + ((uint32_t) links[i].delta) + 1;
+    if (links[i].parent >= num_objects
+        || child_idx >= num_objects)
+      goto end;
+
+    if (links[i].width < 2 || links[i].width > 4) goto end;
+  }
+
+  add_links_to_objects (objects, num_objects,
+                        links, num_real_links);
+
+  hb_blob_destroy (hb_subset_repack_or_fail (table_tag,
+                                             objects,
+                                             num_objects));
+
+end:
+  if (objects)
+  {
+    cleanup (objects, num_objects);
+    free (objects);
+  }
+  free (links);
+
+  return 0;
+}
diff --git a/test/fuzzing/meson.build b/test/fuzzing/meson.build
index 3aba9eb..a39702b 100644
--- a/test/fuzzing/meson.build
+++ b/test/fuzzing/meson.build
@@ -1,6 +1,7 @@
 tests = [
   'hb-shape-fuzzer.cc',
   'hb-subset-fuzzer.cc',
+  'hb-repacker-fuzzer.cc',
   'hb-set-fuzzer.cc',
   'hb-draw-fuzzer.cc',
 ]
@@ -19,6 +20,8 @@
     extra_cpp_args += '-DHB_IS_IN_FUZZER'
   endif
 
+  # TODO tie this to the experimental api setting.
+  extra_cpp_args += '-DHB_EXPERIMENTAL_API'
   exe = executable(test_name, sources,
     cpp_args: cpp_args + extra_cpp_args,
     include_directories: [incconfig, incsrc],