Coverage Report

Created: 2025-08-28 06:11

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