Coverage Report

Created: 2023-06-07 06:29

/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
}