/src/ttf-parser/fuzz/fuzz_targets/fuzz-table.rs
Line | Count | Source |
1 | | // Copyright 2025 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #![no_main] |
16 | | |
17 | | use libfuzzer_sys::fuzz_target; |
18 | | use std::num::NonZeroU16; |
19 | | use ttf_parser::{GlyphId}; |
20 | | use ttf_parser::{ankr, avar, cmap, feat, fvar, gdef, gvar, hmtx, hvar, kern, kerx}; |
21 | | use ttf_parser::{loca, math, maxp, morx, mvar, name, sbix, stat, svg, trak, vhea, vorg, vvar}; |
22 | | |
23 | | fuzz_target!(|fuzz_data: &[u8]| { |
24 | | // Skip this iteration if data is empty |
25 | | if fuzz_data.is_empty() { |
26 | | return; |
27 | | } |
28 | | |
29 | | // Randomly choose a fuzzing target function |
30 | | let choice = fuzz_data[0] % 26; |
31 | | let data = &fuzz_data[1..]; |
32 | | match choice { |
33 | | 0 => { |
34 | | // Fuzz cmap module |
35 | | if let Some(subtable0) = cmap::Subtable0::parse(data) { |
36 | | subtable0.glyph_index(0x41); |
37 | | subtable0.glyph_index(0x42); |
38 | | let mut codepoints = vec![]; |
39 | 1.77k | subtable0.codepoints(|c| codepoints.push(c)); |
40 | | } |
41 | | if let Some(subtable4) = cmap::Subtable4::parse(data) { |
42 | | subtable4.glyph_index(0x41); |
43 | | subtable4.glyph_index(0x42); |
44 | | let mut codepoints = vec![]; |
45 | 23.9M | subtable4.codepoints(|c| codepoints.push(c)); |
46 | | } |
47 | | } |
48 | | 1 => { |
49 | | // Fuzz ankr module |
50 | | if let Some(table) = ankr::Table::parse(NonZeroU16::new(1).unwrap(), data) { |
51 | | if let Some(points) = table.points(GlyphId(0)) { |
52 | | for point in points { |
53 | | let _ = point.x; |
54 | | let _ = point.y; |
55 | | } |
56 | | } |
57 | | } |
58 | | } |
59 | | 2 => { |
60 | | // Fuzz feat module |
61 | | if let Some(feat_table) = feat::Table::parse(data) { |
62 | | for feature in feat_table.names { |
63 | | let _ = feature.exclusive; |
64 | | let _ = feature.default_setting_index; |
65 | | } |
66 | | } |
67 | | } |
68 | | 3 => { |
69 | | // Fuzz hmtx module |
70 | | if let Some(hmtx_table) = hmtx::Table::parse(1, NonZeroU16::new(1).unwrap(), data) { |
71 | | let _ = hmtx_table.number_of_metrics; |
72 | | } |
73 | | } |
74 | | 4 => { |
75 | | // Fuzz maxp module |
76 | | if let Some(maxp_table) = maxp::Table::parse(data) { |
77 | | let _ = maxp_table.number_of_glyphs; |
78 | | } |
79 | | } |
80 | | 5 => { |
81 | | // Fuzz sbix module |
82 | | if let Some(table) = sbix::Table::parse(NonZeroU16::new(1).unwrap(), data) { |
83 | | for strike in table.strikes { |
84 | | for i in 0..strike.len() { |
85 | | if let Some(glyph_data) = strike.get(GlyphId(i as u16)) { |
86 | | let _ = glyph_data.x; |
87 | | let _ = glyph_data.y; |
88 | | let _ = glyph_data.width; |
89 | | let _ = glyph_data.height; |
90 | | let _ = glyph_data.pixels_per_em; |
91 | | let _ = glyph_data.format; |
92 | | } |
93 | | } |
94 | | } |
95 | | } |
96 | | } |
97 | | 6 => { |
98 | | // Fuzz trak module |
99 | | if let Some(trak_table) = trak::Table::parse(data) { |
100 | | for track in trak_table.horizontal.tracks { |
101 | | let _ = track.value; |
102 | | for value in track.values { |
103 | | let _ = value; |
104 | | } |
105 | | } |
106 | | } |
107 | | } |
108 | | 7 => { |
109 | | // Fuzz kern module |
110 | | if let Some(kern_table) = kern::Table::parse(data) { |
111 | | for subtable in kern_table.subtables.into_iter() { |
112 | | if let Some(kern_val) = subtable.glyphs_kerning(GlyphId(1), GlyphId(2)) { |
113 | | let _ = kern_val; |
114 | | } |
115 | | } |
116 | | } |
117 | | } |
118 | | 8 => { |
119 | | // Fuzz kerx module |
120 | | if let Some(kerx_table) = kerx::Table::parse(NonZeroU16::new(1).unwrap(), data) { |
121 | | for subtable in kerx_table.subtables.into_iter() { |
122 | | if let Some(kerx_val) = subtable.glyphs_kerning(GlyphId(1), GlyphId(2)) { |
123 | | let _ = kerx_val; |
124 | | } |
125 | | } |
126 | | } |
127 | | } |
128 | | 9 => { |
129 | | // Fuzz loca module |
130 | | if let Some(loca_table) = loca::Table::parse(NonZeroU16::new(1).unwrap(), ttf_parser::head::IndexToLocationFormat::Short, data) { |
131 | | if let Some(range) = loca_table.glyph_range(GlyphId(1)) { |
132 | | let _ = range.start; |
133 | | let _ = range.end; |
134 | | } |
135 | | } |
136 | | } |
137 | | 10 => { |
138 | | // Fuzz math constants module |
139 | | if let Some(math_table) = math::Table::parse(data) { |
140 | | if let Some(constants) = math_table.constants { |
141 | | let _ = constants.axis_height(); |
142 | | let _ = constants.script_percent_scale_down(); |
143 | | } |
144 | | } |
145 | | } |
146 | | 11 => { |
147 | | // Fuzz math kern info module |
148 | | if let Some(math_table) = math::Table::parse(data) { |
149 | | if let Some(glyph_info) = math_table.glyph_info { |
150 | | if let Some(kern_infos) = glyph_info.kern_infos { |
151 | | if let Some(kern_info) = kern_infos.get(GlyphId(1)) { |
152 | | let _ = kern_info.top_right; |
153 | | let _ = kern_info.bottom_left; |
154 | | } |
155 | | } |
156 | | } |
157 | | } |
158 | | } |
159 | | 12 => { |
160 | | // Fuzz gvar module |
161 | | let _ = gvar::Table::parse(data); |
162 | | } |
163 | | 13 => { |
164 | | // Fuzz hvar module |
165 | | let _ = hvar::Table::parse(data); |
166 | | } |
167 | | 14 => { |
168 | | // Fuzz avar module |
169 | | let _ = avar::Table::parse(data); |
170 | | } |
171 | | 15 => { |
172 | | // Fuzz fvar module |
173 | | if let Some(fvar_table) = fvar::Table::parse(data) { |
174 | | for axis in fvar_table.axes { |
175 | | let _ = axis.tag; |
176 | | } |
177 | | } |
178 | | } |
179 | | 16 => { |
180 | | // Fuzz gdef module |
181 | | if let Some(gdef_table) = gdef::Table::parse(data) { |
182 | | let _ = gdef_table.glyph_class(GlyphId(1)); |
183 | | } |
184 | | } |
185 | | 17 => { |
186 | | // Fuzz morx module |
187 | | if let Some(morx_table) = morx::Table::parse(NonZeroU16::new(1).unwrap(), data) { |
188 | | for chain in morx_table.chains { |
189 | | let _ = chain.default_flags; |
190 | | for feature in chain.features { |
191 | | let _ = feature.kind; |
192 | | } |
193 | | } |
194 | | } |
195 | | } |
196 | | 18 => { |
197 | | // Fuzz mvar module |
198 | | if let Some(mvar_table) = mvar::Table::parse(data) { |
199 | | let _ = mvar_table.metric_offset(ttf_parser::Tag::from_bytes(b"wdth"), &[]); |
200 | | } |
201 | | } |
202 | | 19 => { |
203 | | // Fuzz name module |
204 | | if let Some(name_table) = name::Table::parse(data) { |
205 | | for index in 0..name_table.names.len() { |
206 | | if let Some(name) = name_table.names.get(index) { |
207 | | let _ = name.to_string(); |
208 | | } |
209 | | } |
210 | | } |
211 | | } |
212 | | 20 => { |
213 | | // Fuzz stat module |
214 | | if let Some(stat_table) = stat::Table::parse(data) { |
215 | | for subtable in stat_table.subtables() { |
216 | | let _ = subtable.name_id(); |
217 | | } |
218 | | } |
219 | | } |
220 | | 21 => { |
221 | | // Fuzz svg module |
222 | | if let Some(svg_table) = svg::Table::parse(data) { |
223 | | for index in 0..svg_table.documents.len() { |
224 | | if let Some(svg_doc) = svg_table.documents.get(index) { |
225 | | let _ = svg_doc.glyphs_range(); |
226 | | } |
227 | | } |
228 | | } |
229 | | } |
230 | | 22 => { |
231 | | // Fuzz trak module |
232 | | if let Some(trak_table) = trak::Table::parse(data) { |
233 | | for track in trak_table.horizontal.tracks { |
234 | | let _ = track.value; |
235 | | for value in track.values { |
236 | | let _ = value; |
237 | | } |
238 | | } |
239 | | } |
240 | | } |
241 | | 23 => { |
242 | | // Fuzz vhea module |
243 | | if let Some(vhea_table) = vhea::Table::parse(data) { |
244 | | let _ = vhea_table.ascender; |
245 | | let _ = vhea_table.descender; |
246 | | let _ = vhea_table.line_gap; |
247 | | let _ = vhea_table.number_of_metrics; |
248 | | } |
249 | | } |
250 | | 24 => { |
251 | | // Fuzz vorg module |
252 | | if let Some(vorg_table) = vorg::Table::parse(data) { |
253 | | let _ = vorg_table.default_y; |
254 | | for metrics in vorg_table.metrics { |
255 | | let _ = metrics.glyph_id; |
256 | | let _ = metrics.y; |
257 | | } |
258 | | } |
259 | | } |
260 | | 25 => { |
261 | | // Fuzz vvar module |
262 | | if let Some(vvar_table) = vvar::Table::parse(data) { |
263 | | let _ = vvar_table.advance_offset(GlyphId(1), &[]); |
264 | | let _ = vvar_table.top_side_bearing_offset(GlyphId(1), &[]); |
265 | | let _ = vvar_table.bottom_side_bearing_offset(GlyphId(1), &[]); |
266 | | let _ = vvar_table.vertical_origin_offset(GlyphId(1), &[]); |
267 | | } |
268 | | } |
269 | | _ => {} |
270 | | } |
271 | | }); |