/src/unicode-normalization/fuzz/fuzz_targets/streaming.rs
Line | Count | Source |
1 | | //! Test that the NFC iterator doesn't run needlessly further ahead of its |
2 | | //! underlying iterator. |
3 | | //! |
4 | | //! The NFC iterator is wrapped around the NFD iterator, and it buffers |
5 | | //! up combining characters so that it can sort them once it knows it has |
6 | | //! seen the complete sequence. At that point, it should drain its own |
7 | | //! buffer before consuming more characters from its inner iterator. |
8 | | //! This fuzz target defines a custom iterator which records how many |
9 | | //! times it's called so we can detect if NFC called it too many times. |
10 | | |
11 | | #![no_main] |
12 | | |
13 | | #[macro_use] |
14 | | extern crate libfuzzer_sys; |
15 | | |
16 | | use std::cell::RefCell; |
17 | | use std::rc::Rc; |
18 | | use std::str::Chars; |
19 | | use unicode_normalization::{char::canonical_combining_class, UnicodeNormalization}; |
20 | | |
21 | | const MAX_NONSTARTERS: u32 = 30; |
22 | | |
23 | | #[derive(Debug)] |
24 | | struct Counter<'a> { |
25 | | iter: Chars<'a>, |
26 | | value: Rc<RefCell<u32>>, |
27 | | } |
28 | | |
29 | | impl<'a> Iterator for Counter<'a> { |
30 | | type Item = char; |
31 | | |
32 | 10.2M | fn next(&mut self) -> Option<char> { |
33 | 10.2M | let next = self.iter.next(); |
34 | 10.2M | if let Some(c) = next { |
35 | 10.2M | if canonical_combining_class(c) != 0 { |
36 | 2.33M | *self.value.borrow_mut() += 1; |
37 | 7.89M | } |
38 | 2.12k | } |
39 | 10.2M | next |
40 | 10.2M | } |
41 | | } |
42 | | |
43 | | fuzz_target!(|input: String| { |
44 | | let stream_safe = input.chars().stream_safe().collect::<String>(); |
45 | | |
46 | | let value = Rc::new(RefCell::new(0)); |
47 | | let counter = Counter { |
48 | | iter: stream_safe.chars(), |
49 | | value: Rc::clone(&value), |
50 | | }; |
51 | | for _ in counter.nfc() { |
52 | | // Plus 1: The iterator may consume a starter that begins the next sequence. |
53 | | assert!(*value.borrow() <= MAX_NONSTARTERS + 1); |
54 | | *value.borrow_mut() = 0; |
55 | | } |
56 | | }); |