Coverage Report

Created: 2021-03-22 08:29

/src/wasm-tools/fuzz/fuzz_targets/roundtrip.rs
Line
Count
Source (jump to first uncovered line)
1
#![no_main]
2
3
use libfuzzer_sys::*;
4
use std::str;
5
6
fuzz_target!(|data: &[u8]| {
7
    let string = match str::from_utf8(data) {
8
        Ok(s) => s,
9
        Err(_) => return,
10
    };
11
    // Weed out `(module binary ...)` because when we print the bytes and
12
    // convert it back to binary it's not guaranteed to be exactly the same.
13
    // (think of something like an over-long LEB encoding)
14
    if string.contains("binary") {
15
        return;
16
    }
17
18
    // Also weed out `@custom` custom sections since we don't print those right
19
    // now.
20
    if string.contains("@custom") {
21
        return;
22
    }
23
    let wasm = match wat::parse_str(string) {
24
        Ok(bytes) => bytes,
25
        Err(_) => return,
26
    };
27
28
    // Only roundtrip valid modules for now since invalid modules can often have
29
    // bizarre structures which aren't intended to print correctly or roundtrip
30
    // well.
31
    if wasmparser::validate(&wasm).is_err() {
32
        return;
33
    }
34
35
    // And finally validate that the name section, if present, is valid. This
36
    // can be invalid if names in the name section are too long (e.g. exceeding
37
    // the maximum length of a string). The printing process will skip invalid
38
    // name sections, so if it's invalid then our roundtrip'd bytes will
39
    // trivially not match, but not in an interesting way.
40
    if validate_name_section(&wasm).is_err() {
41
        return;
42
    }
43
    let string2 = match wasmprinter::print_bytes(&wasm) {
44
        Ok(s) => s,
45
        Err(_) => return,
46
    };
47
48
    let wasm2 = wat::parse_str(&string2).unwrap();
49
    if wasm == wasm2 {
50
        return;
51
    }
52
53
    std::fs::write("wasm1.wasm", &wasm).unwrap();
54
    std::fs::write("wasm1.wat", &string).unwrap();
55
    std::fs::write("wasm2.wasm", &wasm2).unwrap();
56
    std::fs::write("wasm2.wat", &string2).unwrap();
57
    panic!("wasm bytes differ on roundtrip");
58
});
59
60
271
fn validate_name_section(wasm: &[u8]) -> wasmparser::Result<()> {
61
    use wasmparser::*;
62
275k
    for payload in Parser::new(0).parse_all(wasm) {
63
275k
        let reader = match payload? {
64
            Payload::CustomSection {
65
209
                name: "name",
66
209
                data_offset,
67
209
                data,
68
                range: _,
69
209
            } => NameSectionReader::new(data, data_offset)?,
70
            _ => continue,
71
        };
72
229
        for section in reader {
73
229
            match section? {
74
5
                Name::Module(n) => {
75
5
                    n.get_name()?;
76
                }
77
124
                Name::Function(n) => {
78
124
                    let mut map = n.get_map()?;
79
125k
                    for _ in 0..map.get_count() {
80
125k
                        map.read()?;
81
                    }
82
                }
83
100
                Name::Local(n) => {
84
100
                    let mut reader = n.get_function_local_reader()?;
85
90.3k
                    for _ in 0..reader.get_count() {
86
90.3k
                        let local_name = reader.read()?;
87
90.3k
                        let mut map = local_name.get_map()?;
88
175k
                        for _ in 0..map.get_count() {
89
175k
                            map.read()?;
90
                        }
91
                    }
92
                }
93
            }
94
        }
95
    }
96
250
    Ok(())
97
271
}