/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-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 | 25.5M | { |
35 | 25.5M | if (*size < sizeof (T)) return false; |
36 | | |
37 | 25.5M | memcpy(out, *data, sizeof (T)); |
38 | | |
39 | 25.5M | *data += sizeof (T); |
40 | 25.5M | *size -= sizeof (T); |
41 | | |
42 | 25.5M | return true; |
43 | 25.5M | } bool read<unsigned int>(unsigned char const**, unsigned long*, unsigned int*) Line | Count | Source | 34 | 2.81k | { | 35 | 2.81k | if (*size < sizeof (T)) return false; | 36 | | | 37 | 2.80k | memcpy(out, *data, sizeof (T)); | 38 | | | 39 | 2.80k | *data += sizeof (T); | 40 | 2.80k | *size -= sizeof (T); | 41 | | | 42 | 2.80k | return true; | 43 | 2.81k | } |
bool read<unsigned short>(unsigned char const**, unsigned long*, unsigned short*) Line | Count | Source | 34 | 10.4M | { | 35 | 10.4M | if (*size < sizeof (T)) return false; | 36 | | | 37 | 10.4M | memcpy(out, *data, sizeof (T)); | 38 | | | 39 | 10.4M | *data += sizeof (T); | 40 | 10.4M | *size -= sizeof (T); | 41 | | | 42 | 10.4M | return true; | 43 | 10.4M | } |
bool read<link_t>(unsigned char const**, unsigned long*, link_t*) Line | Count | Source | 34 | 15.1M | { | 35 | 15.1M | if (*size < sizeof (T)) return false; | 36 | | | 37 | 15.1M | memcpy(out, *data, sizeof (T)); | 38 | | | 39 | 15.1M | *data += sizeof (T); | 40 | 15.1M | *size -= sizeof (T); | 41 | | | 42 | 15.1M | return true; | 43 | 15.1M | } |
|
44 | | |
45 | | void cleanup (hb_object_t* objects, uint16_t num_objects) |
46 | 2.80k | { |
47 | 11.6M | for (uint32_t i = 0; i < num_objects; i++) |
48 | 11.6M | { |
49 | 11.6M | free (objects[i].head); |
50 | 11.6M | free (objects[i].real_links); |
51 | 11.6M | } |
52 | 2.80k | } |
53 | | |
54 | | void add_links_to_objects (hb_object_t* objects, uint16_t num_objects, |
55 | | link_t* links, uint16_t num_links) |
56 | 2.63k | { |
57 | 2.63k | unsigned* link_count = (unsigned*) calloc (num_objects, sizeof (unsigned)); |
58 | | |
59 | 15.1M | for (uint32_t i = 0; i < num_links; i++) |
60 | 15.1M | { |
61 | 15.1M | uint16_t parent_idx = links[i].parent; |
62 | 15.1M | link_count[parent_idx]++; |
63 | 15.1M | } |
64 | | |
65 | 10.4M | for (uint32_t i = 0; i < num_objects; i++) |
66 | 10.4M | { |
67 | 10.4M | objects[i].num_real_links = link_count[i]; |
68 | 10.4M | objects[i].real_links = (hb_link_t*) calloc (link_count[i], sizeof (hb_link_t)); |
69 | 10.4M | objects[i].num_virtual_links = 0; |
70 | 10.4M | objects[i].virtual_links = nullptr; |
71 | 10.4M | } |
72 | | |
73 | 15.1M | for (uint32_t i = 0; i < num_links; i++) |
74 | 15.1M | { |
75 | 15.1M | uint16_t parent_idx = links[i].parent; |
76 | 15.1M | uint16_t child_idx = links[i].child + 1; // All indices are shifted by 1 by the null object. |
77 | 15.1M | hb_link_t* link = &(objects[parent_idx].real_links[link_count[parent_idx] - 1]); |
78 | | |
79 | 15.1M | link->width = links[i].width; |
80 | 15.1M | link->position = links[i].position; |
81 | 15.1M | link->objidx = child_idx; |
82 | 15.1M | link_count[parent_idx]--; |
83 | 15.1M | } |
84 | | |
85 | 2.63k | free (link_count); |
86 | 2.63k | } |
87 | | |
88 | | extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) |
89 | 2.81k | { |
90 | | // TODO(garretrieger): move graph validity checks into repacker graph creation. |
91 | 2.81k | alloc_state = _fuzzing_alloc_state (data, size); |
92 | | |
93 | 2.81k | uint16_t num_objects = 0; |
94 | 2.81k | hb_object_t* objects = nullptr; |
95 | | |
96 | 2.81k | uint16_t num_real_links = 0; |
97 | 2.81k | link_t* links = nullptr; |
98 | | |
99 | 2.81k | hb_tag_t table_tag; |
100 | 2.81k | if (!read<hb_tag_t> (&data, &size, &table_tag)) goto end; |
101 | 2.80k | if (!read<uint16_t> (&data, &size, &num_objects)) goto end; |
102 | | |
103 | 2.80k | objects = (hb_object_t*) calloc (num_objects, sizeof (hb_object_t)); |
104 | 10.4M | for (uint32_t i = 0; i < num_objects; i++) |
105 | 10.4M | { |
106 | 10.4M | uint16_t blob_size; |
107 | 10.4M | if (!read<uint16_t> (&data, &size, &blob_size)) goto end; |
108 | 10.4M | if (size < blob_size) goto end; |
109 | | |
110 | 10.4M | char* copy = (char*) calloc (1, blob_size); |
111 | 10.4M | memcpy (copy, data, blob_size); |
112 | 10.4M | objects[i].head = (char*) copy; |
113 | 10.4M | objects[i].tail = (char*) (copy + blob_size); |
114 | | |
115 | 10.4M | size -= blob_size; |
116 | 10.4M | data += blob_size; |
117 | 10.4M | } |
118 | | |
119 | 2.73k | if (!read<uint16_t> (&data, &size, &num_real_links)) goto end; |
120 | 2.73k | links = (link_t*) calloc (num_real_links, sizeof (link_t)); |
121 | 15.1M | for (uint32_t i = 0; i < num_real_links; i++) |
122 | 15.1M | { |
123 | 15.1M | if (!read<link_t> (&data, &size, &links[i])) goto end; |
124 | | |
125 | 15.1M | if (links[i].parent >= num_objects) |
126 | 72 | goto end; |
127 | 15.1M | } |
128 | | |
129 | 2.63k | add_links_to_objects (objects, num_objects, |
130 | 2.63k | links, num_real_links); |
131 | | |
132 | 2.63k | hb_blob_destroy (hb_subset_repack_or_fail (table_tag, |
133 | 2.63k | objects, |
134 | 2.63k | num_objects)); |
135 | | |
136 | 2.81k | end: |
137 | 2.81k | if (objects) |
138 | 2.80k | { |
139 | 2.80k | cleanup (objects, num_objects); |
140 | 2.80k | free (objects); |
141 | 2.80k | } |
142 | 2.81k | free (links); |
143 | | |
144 | 2.81k | return 0; |
145 | 2.63k | } |