Coverage Report

Created: 2025-12-31 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}