Imported Upstream version 8.2.2
[platform/upstream/harfbuzz.git] / test / fuzzing / hb-repacker-fuzzer.cc
1 #include "hb-fuzzer.hh"
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <assert.h>
7
8 #include "hb-subset-repacker.h"
9
10 typedef struct
11 {
12   uint16_t parent;
13   uint16_t child;
14   uint16_t position;
15   uint8_t width;
16 } link_t;
17
18 /* The fuzzer seed contains a serialized representation of a object graph which forms
19  * the input graph to the repacker call. The binary format is:
20  *
21  * table tag: 4 bytes
22  * number of objects: 2 bytes
23  * objects[number of objects]:
24  *   blob size: 2 bytes
25  *   blob: blob size bytes
26  * num of real links: 2 bytes
27  * links[number of real links]: link_t struct
28  *
29  * TODO(garretrieger): add optional virtual links
30  */
31
32 template <typename T>
33 bool read(const uint8_t** data, size_t* size, T* out)
34 {
35   if (*size < sizeof (T)) return false;
36
37   memcpy(out, *data, sizeof (T));
38
39   *data += sizeof (T);
40   *size -= sizeof (T);
41
42   return true;
43 }
44
45 void cleanup (hb_object_t* objects, uint16_t num_objects)
46 {
47   for (uint32_t i = 0; i < num_objects; i++)
48   {
49     free (objects[i].head);
50     free (objects[i].real_links);
51   }
52 }
53
54 void add_links_to_objects (hb_object_t* objects, uint16_t num_objects,
55                            link_t* links, uint16_t num_links)
56 {
57   unsigned* link_count = (unsigned*) calloc (num_objects, sizeof (unsigned));
58
59   for (uint32_t i = 0; i < num_links; i++)
60   {
61     uint16_t parent_idx = links[i].parent;
62     link_count[parent_idx]++;
63   }
64
65   for (uint32_t i = 0; i < num_objects; i++)
66   {
67     objects[i].num_real_links = link_count[i];
68     objects[i].real_links = (hb_link_t*) calloc (link_count[i], sizeof (hb_link_t));
69     objects[i].num_virtual_links = 0;
70     objects[i].virtual_links = nullptr;
71   }
72
73   for (uint32_t i = 0; i < num_links; i++)
74   {
75     uint16_t parent_idx = links[i].parent;
76     uint16_t child_idx = links[i].child + 1; // All indices are shifted by 1 by the null object.
77     hb_link_t* link = &(objects[parent_idx].real_links[link_count[parent_idx] - 1]);
78
79     link->width = links[i].width;
80     link->position = links[i].position;
81     link->objidx = child_idx;
82     link_count[parent_idx]--;
83   }
84
85   free (link_count);
86 }
87
88 extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
89 {
90   // TODO(garretrieger): move graph validity checks into repacker graph creation.
91   alloc_state = _fuzzing_alloc_state (data, size);
92
93   uint16_t num_objects = 0;
94   hb_object_t* objects = nullptr;
95
96   uint16_t num_real_links = 0;
97   link_t* links = nullptr;
98
99   hb_tag_t table_tag;
100   if (!read<hb_tag_t> (&data, &size, &table_tag)) goto end;
101   if (!read<uint16_t> (&data, &size, &num_objects)) goto end;
102
103   objects = (hb_object_t*) calloc (num_objects, sizeof (hb_object_t));
104   for (uint32_t i = 0; i < num_objects; i++)
105   {
106     uint16_t blob_size;
107     if (!read<uint16_t> (&data, &size, &blob_size)) goto end;
108     if (size < blob_size) goto end;
109
110     char* copy = (char*) calloc (1, blob_size);
111     memcpy (copy, data, blob_size);
112     objects[i].head = (char*) copy;
113     objects[i].tail = (char*) (copy + blob_size);
114
115     size -= blob_size;
116     data += blob_size;
117   }
118
119   if (!read<uint16_t> (&data, &size, &num_real_links)) goto end;
120   links = (link_t*) calloc (num_real_links, sizeof (link_t));
121   for (uint32_t i = 0; i < num_real_links; i++)
122   {
123     if (!read<link_t> (&data, &size, &links[i])) goto end;
124
125     if (links[i].parent >= num_objects)
126       goto end;
127   }
128
129   add_links_to_objects (objects, num_objects,
130                         links, num_real_links);
131
132   hb_blob_destroy (hb_subset_repack_or_fail (table_tag,
133                                              objects,
134                                              num_objects));
135
136 end:
137   if (objects)
138   {
139     cleanup (objects, num_objects);
140     free (objects);
141   }
142   free (links);
143
144   return 0;
145 }