From deca30b2684f5580606ad614bc3ffb6c35e887a5 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Thu, 8 Sep 2022 21:10:06 +0000 Subject: [PATCH] [repacker] get repacker fuzzer working. Additionally add helper method that allows a graph to be saved as a fuzzer seed. --- src/graph/graph.hh | 50 ++++++++++++++++++++++++++++++ src/hb-repacker.hh | 2 +- test/fuzzing/hb-repacker-fuzzer.cc | 13 +++++--- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/graph/graph.hh b/src/graph/graph.hh index 20d646300..b81f869d5 100644 --- a/src/graph/graph.hh +++ b/src/graph/graph.hh @@ -953,6 +953,56 @@ struct graph_t return true; } +#if 0 + /* + * Saves the current graph to a packed binary format which the repacker fuzzer takes + * as a seed. + */ + void save_fuzzer_seed (hb_tag_t tag) const + { + FILE* f = fopen ("./repacker_fuzzer_seed", "w"); + fwrite ((void*) &tag, sizeof (tag), 1, f); + + uint16_t num_objects = vertices_.length; + fwrite ((void*) &num_objects, sizeof (num_objects), 1, f); + + for (const auto& v : vertices_) + { + uint16_t blob_size = v.table_size (); + fwrite ((void*) &blob_size, sizeof (blob_size), 1, f); + fwrite ((const void*) v.obj.head, blob_size, 1, f); + } + + uint16_t link_count = 0; + for (const auto& v : vertices_) + link_count += v.obj.real_links.length; + + fwrite ((void*) &link_count, sizeof (link_count), 1, f); + + typedef struct + { + uint16_t parent; + uint16_t child; + uint16_t position; + uint8_t width; + } link_t; + + for (unsigned i = 0; i < vertices_.length; i++) + { + for (const auto& l : vertices_[i].obj.real_links) + { + link_t link { + (uint16_t) i, (uint16_t) l.objidx, + (uint16_t) l.position, (uint8_t) l.width + }; + fwrite ((void*) &link, sizeof (link), 1, f); + } + } + + fclose (f); + } +#endif + void print_orphaned_nodes () { if (!DEBUG_ENABLED(SUBSET_REPACK)) return; diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh index ba305577b..f6ee403f5 100644 --- a/src/hb-repacker.hh +++ b/src/hb-repacker.hh @@ -378,7 +378,7 @@ hb_resolve_overflows (const T& packed, graph_t sorted_graph (packed); if (!sorted_graph.is_fully_connected ()) { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Input graph is not fully connected."); + sorted_graph.print_orphaned_nodes (); return nullptr; } diff --git a/test/fuzzing/hb-repacker-fuzzer.cc b/test/fuzzing/hb-repacker-fuzzer.cc index 0f58048e6..fb73df6d5 100644 --- a/test/fuzzing/hb-repacker-fuzzer.cc +++ b/test/fuzzing/hb-repacker-fuzzer.cc @@ -31,7 +31,10 @@ bool read(const uint8_t** data, size_t* size, T* out) void cleanup (hb_object_t* objects, uint16_t num_objects) { for (uint32_t i = 0; i < num_objects; i++) + { + free (objects[i].head); free (objects[i].real_links); + } } void add_links_to_objects (hb_object_t* objects, uint16_t num_objects, @@ -56,7 +59,7 @@ void add_links_to_objects (hb_object_t* objects, uint16_t num_objects, for (uint32_t i = 0; i < num_links; i++) { uint16_t parent_idx = links[i].parent; - uint16_t child_idx = links[i].child; + uint16_t child_idx = links[i].child + 1; // All indices are shifted by 1 by the null object. hb_link_t* link = &(objects[parent_idx].real_links[link_count[parent_idx] - 1]); link->width = links[i].width; @@ -89,8 +92,10 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) if (!read (&data, &size, &blob_size)) goto end; if (size < blob_size) goto end; - objects[i].head = (char*) data; - objects[i].tail = (char*) (data + blob_size); + char* copy = (char*) calloc (1, blob_size); + memcpy (copy, data, blob_size); + objects[i].head = (char*) copy; + objects[i].tail = (char*) (copy + blob_size); size -= blob_size; data += blob_size; @@ -103,7 +108,7 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) if (!read (&data, &size, &links[i])) goto end; if (links[i].parent >= num_objects - || links[i].child >= links[i].parent) // Enforces DAG graph + || links[i].child > links[i].parent) // Enforces DAG graph goto end; if (links[i].width < 2 || links[i].width > 4) goto end;