146 lines
3.6 KiB
C++
146 lines
3.6 KiB
C++
#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 child;
|
|
uint16_t position;
|
|
uint8_t width;
|
|
} link_t;
|
|
|
|
/* The fuzzer seed contains a serialized representation of a object graph which forms
|
|
* the input graph to the repacker call. The binary format is:
|
|
*
|
|
* table tag: 4 bytes
|
|
* number of objects: 2 bytes
|
|
* objects[number of objects]:
|
|
* blob size: 2 bytes
|
|
* blob: blob size bytes
|
|
* num of real links: 2 bytes
|
|
* links[number of real links]: link_t struct
|
|
*
|
|
* TODO(garretrieger): add optional virtual links
|
|
*/
|
|
|
|
template <typename T>
|
|
bool read(const uint8_t** data, size_t* size, T* out)
|
|
{
|
|
if (*size < sizeof (T)) return false;
|
|
|
|
memcpy(out, *data, sizeof (T));
|
|
|
|
*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].head);
|
|
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].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;
|
|
link->position = links[i].position;
|
|
link->objidx = child_idx;
|
|
link_count[parent_idx]--;
|
|
}
|
|
|
|
free (link_count);
|
|
}
|
|
|
|
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
|
{
|
|
// TODO(garretrieger): move graph validity checks into repacker graph creation.
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
if (links[i].parent >= num_objects)
|
|
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;
|
|
}
|