/src/harfbuzz/test/fuzzing/hb-repacker-fuzzer.cc
Line | Count | Source |
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-serialize.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 | 0 | { |
35 | 0 | if (*size < sizeof (T)) return false; |
36 | | |
37 | 0 | memcpy(out, *data, sizeof (T)); |
38 | |
|
39 | 0 | *data += sizeof (T); |
40 | 0 | *size -= sizeof (T); |
41 | |
|
42 | 0 | return true; |
43 | 0 | } Unexecuted instantiation: bool read<unsigned int>(unsigned char const**, unsigned long*, unsigned int*) Unexecuted instantiation: bool read<unsigned short>(unsigned char const**, unsigned long*, unsigned short*) Unexecuted instantiation: bool read<link_t>(unsigned char const**, unsigned long*, link_t*) |
44 | | |
45 | | void cleanup (hb_subset_serialize_object_t* objects, uint16_t num_objects) |
46 | 0 | { |
47 | 0 | for (uint32_t i = 0; i < num_objects; i++) |
48 | 0 | { |
49 | 0 | free (objects[i].head); |
50 | 0 | free (objects[i].real_links); |
51 | 0 | } |
52 | 0 | } |
53 | | |
54 | | void add_links_to_objects (hb_subset_serialize_object_t* objects, uint16_t num_objects, |
55 | | link_t* links, uint16_t num_links) |
56 | 0 | { |
57 | 0 | unsigned* link_count = (unsigned*) calloc (num_objects, sizeof (unsigned)); |
58 | |
|
59 | 0 | for (uint32_t i = 0; i < num_links; i++) |
60 | 0 | { |
61 | 0 | uint16_t parent_idx = links[i].parent; |
62 | 0 | link_count[parent_idx]++; |
63 | 0 | } |
64 | |
|
65 | 0 | for (uint32_t i = 0; i < num_objects; i++) |
66 | 0 | { |
67 | 0 | objects[i].num_real_links = link_count[i]; |
68 | 0 | objects[i].real_links = (hb_subset_serialize_link_t*) calloc (link_count[i], sizeof (hb_subset_serialize_link_t)); |
69 | 0 | objects[i].num_virtual_links = 0; |
70 | 0 | objects[i].virtual_links = nullptr; |
71 | 0 | } |
72 | |
|
73 | 0 | for (uint32_t i = 0; i < num_links; i++) |
74 | 0 | { |
75 | 0 | uint16_t parent_idx = links[i].parent; |
76 | 0 | uint16_t child_idx = links[i].child + 1; // All indices are shifted by 1 by the null object. |
77 | 0 | hb_subset_serialize_link_t* link = &(objects[parent_idx].real_links[link_count[parent_idx] - 1]); |
78 | |
|
79 | 0 | link->width = links[i].width; |
80 | 0 | link->position = links[i].position; |
81 | 0 | link->objidx = child_idx; |
82 | 0 | link_count[parent_idx]--; |
83 | 0 | } |
84 | |
|
85 | 0 | free (link_count); |
86 | 0 | } |
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_subset_serialize_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_subset_serialize_object_t*) calloc (num_objects, sizeof (hb_subset_serialize_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_serialize_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 | | } |