|
1 | 1 | #![no_main] |
2 | 2 | use libfuzzer_sys::fuzz_target; |
| 3 | +use std::hint::black_box; |
3 | 4 |
|
4 | | -use quick_xml::events::Event; |
5 | | -use quick_xml::reader::Reader; |
| 5 | +use quick_xml::{events::Event, reader::Reader, writer::Writer}; |
6 | 6 | use std::io::Cursor; |
7 | 7 |
|
8 | | -fuzz_target!(|data: &[u8]| { |
9 | | - // fuzzed code goes here |
10 | | - let cursor = Cursor::new(data); |
11 | | - let mut reader = Reader::from_reader(cursor); |
| 8 | +macro_rules! debug_format { |
| 9 | + ($x:expr) => { |
| 10 | + let _unused = std::hint::black_box(format!("{:?}", $x)); |
| 11 | + }; |
| 12 | +} |
| 13 | + |
| 14 | +fn round_trip<R>(reader: &mut Reader<R>) -> () |
| 15 | +where |
| 16 | + R: std::io::BufRead, |
| 17 | +{ |
| 18 | + let mut writer = Writer::new(Cursor::new(Vec::new())); |
12 | 19 | let mut buf = vec![]; |
| 20 | + let reader = reader |
| 21 | + .expand_empty_elements(true) |
| 22 | + .trim_text(true) |
| 23 | + .trim_text_end(true); |
13 | 24 | loop { |
14 | | - match reader.read_event_into(&mut buf) { |
| 25 | + let event_result = reader.read_event_into(&mut buf); |
| 26 | + if let Ok(ref event) = event_result { |
| 27 | + let _event = black_box(event.borrow()); |
| 28 | + let _event = black_box(event.as_ref()); |
| 29 | + debug_format!(event); |
| 30 | + debug_format!(writer.write_event(event)); |
| 31 | + } |
| 32 | + match event_result { |
15 | 33 | Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e)) => { |
| 34 | + debug_format!(e); |
| 35 | + debug_format!(e.name()); |
16 | 36 | for a in e.attributes() { |
| 37 | + debug_format!(a); |
17 | 38 | if a.ok().map_or(false, |a| a.unescape_value().is_err()) { |
18 | 39 | break; |
19 | 40 | } |
20 | 41 | } |
21 | 42 | } |
22 | | - Ok(Event::Text(ref e)) | Ok(Event::Comment(ref e)) |
| 43 | + Ok(Event::Text(ref e)) |
| 44 | + | Ok(Event::Comment(ref e)) |
23 | 45 | | Ok(Event::PI(ref e)) |
24 | 46 | | Ok(Event::DocType(ref e)) => { |
25 | | - if e.unescape().is_err() { |
| 47 | + debug_format!(e); |
| 48 | + if let Err(err) = e.unescape() { |
| 49 | + debug_format!(err); |
26 | 50 | break; |
27 | 51 | } |
28 | 52 | } |
29 | 53 | Ok(Event::CData(e)) => { |
30 | | - if e.escape().is_err() { |
| 54 | + if let Err(err) = e.escape() { |
| 55 | + let _displayed = black_box(format!("{}", err)); |
| 56 | + debug_format!(err); |
31 | 57 | break; |
32 | 58 | } |
33 | 59 | } |
34 | 60 | Ok(Event::Decl(ref e)) => { |
35 | | - let _ = e.version(); |
36 | | - let _ = e.encoding(); |
37 | | - let _ = e.standalone(); |
| 61 | + debug_format!(e); |
| 62 | + let _ = black_box(e.version()); |
| 63 | + let _ = black_box(e.encoding()); |
| 64 | + let _ = black_box(e.standalone()); |
| 65 | + } |
| 66 | + Ok(Event::End(e)) => { |
| 67 | + debug_format!(e.local_name()); |
| 68 | + let name = e.name(); |
| 69 | + debug_format!(name); |
| 70 | + debug_format!(name.prefix()); |
| 71 | + debug_format!(name.local_name()); |
| 72 | + debug_format!(name.decompose()); |
| 73 | + debug_format!(name.as_namespace_binding()); |
| 74 | + debug_format!(e); |
| 75 | + } |
| 76 | + Err(e) => { |
| 77 | + debug_format!(e); |
| 78 | + break; |
38 | 79 | } |
39 | | - Ok(Event::End(_)) => (), |
40 | | - Ok(Event::Eof) | Err(..) => break, |
| 80 | + Ok(Event::Eof) => break, |
41 | 81 | } |
42 | 82 | buf.clear(); |
43 | 83 | } |
| 84 | + let _round_trip = std::hint::black_box(writer.into_inner().into_inner()); |
| 85 | +} |
| 86 | + |
| 87 | +fuzz_target!(|data: &[u8]| { |
| 88 | + // From reader |
| 89 | + let cursor = Cursor::new(data); |
| 90 | + let mut reader = Reader::from_reader(cursor); |
| 91 | + _ = std::hint::black_box(round_trip(&mut reader)); |
| 92 | + |
| 93 | + // From str |
| 94 | + if let Ok(s) = std::str::from_utf8(data) { |
| 95 | + let mut reader = Reader::from_str(s); |
| 96 | + _ = std::hint::black_box(round_trip(&mut reader)); |
| 97 | + } |
44 | 98 | }); |
0 commit comments