/src/ttf-parser/fuzz/fuzz_targets/fuzz-base.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 ttf_parser::{Face, GlyphId, name_id}; |
19 | | |
20 | 11.0k | fn get_fuzzed_char(data: &[u8]) -> char { |
21 | 11.0k | if data.len() >= 4 { |
22 | 11.0k | let code_point = u32::from_le_bytes([data[0], data[1], data[2], data[3]]); |
23 | 11.0k | std::char::from_u32(code_point).unwrap_or('A') |
24 | | } else { |
25 | 20 | 'A' |
26 | | } |
27 | 11.0k | } |
28 | | |
29 | | fuzz_target!(|data: &[u8]| { |
30 | | // Skip this iteration if no data is provided |
31 | | if data.is_empty() { |
32 | | return; |
33 | | } |
34 | | |
35 | | let choice = data[0] % 15; |
36 | | let fuzz_data = &data[1..]; |
37 | | |
38 | | let face_result = Face::parse(fuzz_data, 0); |
39 | | let id = if !data.is_empty() { data[0] as u16 } else { 0 }; |
40 | | let glyph_id = GlyphId(id); |
41 | | let random_char = get_fuzzed_char(fuzz_data); |
42 | | |
43 | | // Randomly fuzz functions from base ttf-parser |
44 | | match choice { |
45 | | 0 => { |
46 | | if let Ok(face) = face_result { |
47 | | let mut family_names = Vec::new(); |
48 | | for name in face.names() { |
49 | | if name.name_id == name_id::FULL_NAME && name.is_unicode() { |
50 | | if let Some(family_name) = name.to_string() { |
51 | | let language = name.language(); |
52 | | family_names.push(format!( |
53 | | "{} ({}, {})", |
54 | | family_name, |
55 | | language.primary_language(), |
56 | | language.region() |
57 | | )); |
58 | | } |
59 | | } |
60 | | } |
61 | | let _ = family_names; |
62 | | } |
63 | | }, |
64 | | 1 => { |
65 | | if let Ok(face) = face_result { |
66 | | let _ = face.units_per_em(); |
67 | | let _ = face.ascender(); |
68 | | let _ = face.descender(); |
69 | | let _ = face.line_gap(); |
70 | | let _ = face.global_bounding_box(); |
71 | | } |
72 | | }, |
73 | | 2 => { |
74 | | if let Ok(face) = face_result { |
75 | | let _ = face.is_regular(); |
76 | | let _ = face.is_bold(); |
77 | | let _ = face.is_italic(); |
78 | | let _ = face.is_oblique(); |
79 | | let _ = face.is_variable(); |
80 | | } |
81 | | }, |
82 | | 3 => { |
83 | | if let Ok(face) = face_result { |
84 | | let _ = face.number_of_glyphs(); |
85 | | let _ = face.glyph_bounding_box(glyph_id); |
86 | | let _ = face.glyph_hor_advance(glyph_id); |
87 | | let _ = face.glyph_index(random_char); |
88 | | } |
89 | | }, |
90 | | 4 => { |
91 | | if let Ok(face) = face_result { |
92 | | let _ = face.underline_metrics(); |
93 | | let _ = face.strikeout_metrics(); |
94 | | let _ = face.subscript_metrics(); |
95 | | let _ = face.superscript_metrics(); |
96 | | } |
97 | | }, |
98 | | 5 => { |
99 | | if let Ok(face) = face_result { |
100 | | let post_script_name = face.names().into_iter() |
101 | 94 | .find(|name| name.name_id == name_id::POST_SCRIPT_NAME && name.is_unicode()) |
102 | 6 | .and_then(|name| name.to_string()); |
103 | | let _ = post_script_name; |
104 | | } |
105 | | }, |
106 | | 6 => { |
107 | | if let Ok(face) = face_result { |
108 | | let _ = face.glyph_raster_image(glyph_id, u16::MAX); |
109 | | } |
110 | | }, |
111 | | 7 => { |
112 | | if let Ok(face) = face_result { |
113 | | if let Some(stat) = face.tables().stat { |
114 | | for axis in stat.axes { |
115 | | let _ = axis.tag; |
116 | | } |
117 | | } |
118 | | } |
119 | | }, |
120 | | 8 => { |
121 | | if let Ok(face) = face_result { |
122 | | if let Some(svg_table) = face.tables().svg { |
123 | | let _ = svg_table.documents.find(glyph_id); |
124 | | } |
125 | | } |
126 | | }, |
127 | | 9 => { |
128 | | if let Ok(face) = face_result { |
129 | | let _ = face.permissions(); |
130 | | let _ = face.is_variable(); |
131 | | } |
132 | | }, |
133 | | 10 => { |
134 | | if let Ok(face) = face_result { |
135 | | let _ = face.glyph_hor_side_bearing(glyph_id); |
136 | | let _ = face.glyph_ver_advance(glyph_id); |
137 | | let _ = face.glyph_ver_side_bearing(glyph_id); |
138 | | } |
139 | | }, |
140 | | 11 => { |
141 | | if let Ok(face) = face_result { |
142 | | let _ = face.tables().os2; |
143 | | } |
144 | | }, |
145 | | 12 => { |
146 | | if let Ok(face) = face_result { |
147 | | let _ = face.tables().head; |
148 | | } |
149 | | }, |
150 | | 13 => { |
151 | | if let Ok(face) = face_result { |
152 | | let _ = face.tables().maxp; |
153 | | } |
154 | | }, |
155 | | 14 => { |
156 | | if let Ok(face) = face_result { |
157 | | let _ = face.tables().hhea; |
158 | | } |
159 | | }, |
160 | | _ => return, |
161 | | } |
162 | | }); |