Coverage Report

Created: 2023-04-25 07:07

/src/wasm-tools/fuzz/fuzz_targets/incremental-parse.rs
Line
Count
Source
1
#![no_main]
2
3
use libfuzzer_sys::*;
4
use wasmparser::*;
5
use Payload::*;
6
7
// Simulate receiving chunks of data by fuzzing over a `Vec<Vec<u8>>` where each
8
// element of the outer vec is a chunk of data we received.
9
//
10
// The assertion here is that parsing everything in one go should always produce
11
// the exact same results as an incremental parse.
12
fuzz_target!(|data: Vec<Vec<u8>>| {
13
    drop(env_logger::try_init());
14
15
    // Concatenate everything together, create our expected iterator of
16
    // payloads, and then write out `input.wasm` if debugging is enabled.
17
41.1M
    let everything = data.iter().flat_map(|a| a).copied().collect::<Vec<_>>();
18
    let mut expected = Parser::new(0).parse_all(&everything);
19
    if log::log_enabled!(log::Level::Debug) {
20
        std::fs::write("input.wasm", &everything).unwrap();
21
    }
22
23
    // Create our parser as well as a stack of nested parsers for parsing nested
24
    // modules.
25
    let mut stack = Vec::new();
26
    let mut parser = Parser::new(0);
27
28
    // We'll be parsing data from `buf` starting at `pos`, and we translate
29
    // `data` into an iterator of chunks so when requested we'll take another
30
    // chunk of data and feed it in.
31
    let mut pos = 0;
32
    let mut buf = Vec::new();
33
    let mut data = data.into_iter().peekable();
34
    loop {
35
        log::debug!("parsing {}..{}", pos, buf.len());
36
        let payload = match parser.parse(&buf[pos..], data.peek().is_none()) {
37
            // If more data is requested then we're guaranteed that `data`
38
            // should have another element in its iterato, so pull that off and
39
            // add it to the end of the `buf`.
40
            Ok(Chunk::NeedMoreData(_n)) => {
41
                buf.extend(data.next().unwrap());
42
                continue;
43
            }
44
            Ok(Chunk::Parsed { consumed, payload }) => {
45
                log::debug!("parsed {} bytes", consumed);
46
                pos += consumed;
47
                payload
48
            }
49
50
            // On failure we should receive the same failure as if we did a full
51
            // parse.
52
            Err(actual) => {
53
                let expected = expected
54
                    .next()
55
                    .expect("full parse stopped early")
56
                    .err()
57
                    .expect("full parse didn't return an error");
58
                assert_eq!(expected.offset(), actual.offset());
59
                assert_eq!(expected.message(), actual.message());
60
                break;
61
            }
62
        };
63
        log::debug!("parsed payload {:?}", payload);
64
        let expected_payload = expected
65
            .next()
66
            .expect("full parse stopped early")
67
            .expect("full parse failed but incremental succeeded");
68
        match (payload, expected_payload) {
69
            (End(_), End(_)) => match stack.pop() {
70
                Some(p) => parser = p,
71
                None => {
72
                    log::debug!("no more parsers");
73
                    assert!(expected.next().is_none());
74
                    break;
75
                }
76
            },
77
            (
78
                Version {
79
                    num: a,
80
                    encoding: ae,
81
                    range: ar,
82
                },
83
                Version {
84
                    num: b,
85
                    encoding: be,
86
                    range: br,
87
                },
88
            ) => {
89
                assert_eq!(a, b);
90
                assert_eq!(ae, be);
91
                assert_eq!(ar, br);
92
            }
93
94
            (TypeSection(a), TypeSection(b)) => assert_eq!(a.range(), b.range()),
95
            (ImportSection(a), ImportSection(b)) => assert_eq!(a.range(), b.range()),
96
            (FunctionSection(a), FunctionSection(b)) => assert_eq!(a.range(), b.range()),
97
            (TableSection(a), TableSection(b)) => assert_eq!(a.range(), b.range()),
98
            (MemorySection(a), MemorySection(b)) => assert_eq!(a.range(), b.range()),
99
            (GlobalSection(a), GlobalSection(b)) => assert_eq!(a.range(), b.range()),
100
            (ExportSection(a), ExportSection(b)) => assert_eq!(a.range(), b.range()),
101
            (TagSection(a), TagSection(b)) => assert_eq!(a.range(), b.range()),
102
            (StartSection { func: a, range: ar }, StartSection { func: b, range: br }) => {
103
                assert_eq!(a, b);
104
                assert_eq!(ar, br);
105
            }
106
            (ElementSection(a), ElementSection(b)) => assert_eq!(a.range(), b.range()),
107
            (
108
                DataCountSection {
109
                    count: a,
110
                    range: ar,
111
                },
112
                DataCountSection {
113
                    count: b,
114
                    range: br,
115
                },
116
            ) => {
117
                assert_eq!(a, b);
118
                assert_eq!(ar, br);
119
            }
120
            (DataSection(a), DataSection(b)) => assert_eq!(a.range(), b.range()),
121
            (CustomSection(ca), CustomSection(cb)) => {
122
                assert_eq!(ca.name(), cb.name());
123
                assert_eq!(ca.data_offset(), cb.data_offset());
124
                assert_eq!(ca.data(), cb.data());
125
                assert_eq!(ca.range(), cb.range());
126
            }
127
            (
128
                CodeSectionStart {
129
                    count: a,
130
                    range: ar,
131
                    size: asz,
132
                },
133
                CodeSectionStart {
134
                    count: b,
135
                    range: br,
136
                    size: bsz,
137
                },
138
            ) => {
139
                assert_eq!(a, b);
140
                assert_eq!(ar, br);
141
                assert_eq!(asz, bsz);
142
            }
143
144
            (CodeSectionEntry(a), CodeSectionEntry(b)) => {
145
                assert_eq!(a.get_binary_reader().range(), b.get_binary_reader().range());
146
            }
147
148
            (
149
                ModuleSection {
150
                    parser: p,
151
                    range: a,
152
                },
153
                ModuleSection { range: b, .. },
154
            ) => {
155
                assert_eq!(a, b);
156
                stack.push(parser);
157
                parser = p;
158
            }
159
            (InstanceSection(a), InstanceSection(b)) => assert_eq!(a.range(), b.range()),
160
            (
161
                ComponentSection {
162
                    parser: p,
163
                    range: a,
164
                },
165
                ComponentSection { range: b, .. },
166
            ) => {
167
                assert_eq!(a, b);
168
                stack.push(parser);
169
                parser = p;
170
            }
171
            (ComponentInstanceSection(a), ComponentInstanceSection(b)) => {
172
                assert_eq!(a.range(), b.range())
173
            }
174
            (ComponentAliasSection(a), ComponentAliasSection(b)) => {
175
                assert_eq!(a.range(), b.range())
176
            }
177
            (ComponentTypeSection(a), ComponentTypeSection(b)) => assert_eq!(a.range(), b.range()),
178
            (ComponentCanonicalSection(a), ComponentCanonicalSection(b)) => {
179
                assert_eq!(a.range(), b.range())
180
            }
181
            (ComponentStartSection { range: a, .. }, ComponentStartSection { range: b, .. }) => {
182
                assert_eq!(a, b)
183
            }
184
            (ComponentImportSection(a), ComponentImportSection(b)) => {
185
                assert_eq!(a.range(), b.range())
186
            }
187
            (ComponentExportSection(a), ComponentExportSection(b)) => {
188
                assert_eq!(a.range(), b.range())
189
            }
190
            (CoreTypeSection(a), CoreTypeSection(b)) => {
191
                assert_eq!(a.range(), b.range())
192
            }
193
194
            (
195
                UnknownSection {
196
                    id: a,
197
                    contents: ac,
198
                    range: ar,
199
                },
200
                UnknownSection {
201
                    id: b,
202
                    contents: bc,
203
                    range: br,
204
                },
205
            ) => {
206
                assert_eq!(a, b);
207
                assert_eq!(ar, br);
208
                assert_eq!(ac, bc);
209
            }
210
211
            (a, b) => {
212
                panic!("expected {:?}\ngot {:?}", b, a);
213
            }
214
        }
215
    }
216
});