/src/ttf-parser/fuzz/fuzz_targets/fuzz-aat.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, apple_layout::Lookup}; |
20 | | |
21 | 161 | fn u16_to_u8_vec(data: &[u16]) -> Vec<u8> { |
22 | 161 | let mut u8_data = Vec::with_capacity(data.len() * 2); |
23 | 617 | for &value in data { |
24 | 456 | u8_data.push((value >> 8) as u8); |
25 | 456 | u8_data.push(value as u8); |
26 | 456 | } |
27 | 161 | u8_data |
28 | 161 | } |
29 | | |
30 | | fuzz_target!(|data: &[u8]| { |
31 | | // Skip this iteration if data not enough |
32 | | if data.len() < 4 { |
33 | | return; |
34 | | } |
35 | | |
36 | | let (format_data, rest) = data.split_at(2); |
37 | | let format = u16::from_be_bytes([format_data[0], format_data[1]]); |
38 | | |
39 | 172 | let random_u16 = |data: &[u8], idx: usize| -> Option<u16> { |
40 | 172 | if data.len() > idx + 1 { |
41 | 161 | Some(u16::from_be_bytes([data[idx], data[idx + 1]])) |
42 | | } else { |
43 | 11 | None |
44 | | } |
45 | 172 | }; |
46 | | |
47 | | let lookup_len = NonZeroU16::new(1).unwrap(); |
48 | | |
49 | | // Use valid fromat 0 2 4 6 8 10 for fuzzing chioce |
50 | | match format { |
51 | | 0 => { |
52 | | if let Some(value) = random_u16(rest, 0) { |
53 | | let lookup_data = u16_to_u8_vec(&[0, value]); |
54 | | if let Some(table) = Lookup::parse(lookup_len, &lookup_data) { |
55 | | let _ = table.value(GlyphId(0)); |
56 | | let _ = table.value(GlyphId(1)); |
57 | | } |
58 | | } |
59 | | } |
60 | | 2 => { |
61 | | if let Some(segment_size) = random_u16(rest, 2) { |
62 | | let lookup_data = u16_to_u8_vec(&[2, segment_size, 1]); |
63 | | if let Some(table) = Lookup::parse(lookup_len, &lookup_data) { |
64 | | let _ = table.value(GlyphId(118)); |
65 | | let _ = table.value(GlyphId(5)); |
66 | | } |
67 | | } |
68 | | } |
69 | | 4 => { |
70 | | if let Some(segment_size) = random_u16(rest, 2) { |
71 | | let lookup_data = u16_to_u8_vec(&[4, segment_size, 1]); |
72 | | if let Some(table) = Lookup::parse(lookup_len, &lookup_data) { |
73 | | let _ = table.value(GlyphId(118)); |
74 | | let _ = table.value(GlyphId(7)); |
75 | | } |
76 | | } |
77 | | } |
78 | | 6 => { |
79 | | if let Some(segment_size) = random_u16(rest, 2) { |
80 | | let lookup_data = u16_to_u8_vec(&[6, segment_size]); |
81 | | if let Some(table) = Lookup::parse(lookup_len, &lookup_data) { |
82 | | let _ = table.value(GlyphId(0)); |
83 | | let _ = table.value(GlyphId(10)); |
84 | | } |
85 | | } |
86 | | } |
87 | | 8 => { |
88 | | if let Some(glyph_count) = random_u16(rest, 2) { |
89 | | let lookup_data = u16_to_u8_vec(&[8, 0, glyph_count]); |
90 | | if let Some(table) = Lookup::parse(lookup_len, &lookup_data) { |
91 | | let _ = table.value(GlyphId(0)); |
92 | | let _ = table.value(GlyphId(5)); |
93 | | } |
94 | | } |
95 | | } |
96 | | 10 => { |
97 | | if let Some(value_size) = random_u16(rest, 2) { |
98 | | let lookup_data = u16_to_u8_vec(&[10, value_size, 0]); |
99 | | if let Some(table) = Lookup::parse(lookup_len, &lookup_data) { |
100 | | let _ = table.value(GlyphId(0)); |
101 | | let _ = table.value(GlyphId(1)); |
102 | | } |
103 | | } |
104 | | } |
105 | | _ => { |
106 | | // Ignore invliad format of 1 3 5 7 9 |
107 | | } |
108 | | } |
109 | | }); |