Coverage Report

Created: 2023-04-25 07:07

/src/wasm-tools/fuzz/fuzz_targets/roundtrip-wit.rs
Line
Count
Source (jump to first uncovered line)
1
#![no_main]
2
3
use libfuzzer_sys::fuzz_target;
4
use std::collections::HashMap;
5
use std::path::Path;
6
use wasm_encoder::{CustomSection, Encode, Section};
7
use wit_component::*;
8
use wit_parser::{Resolve, SourceMap};
9
10
fuzz_target!(|data: &[u8]| {
11
    drop(env_logger::try_init());
12
13
    let mut u = arbitrary::Unstructured::new(data);
14
6.58k
    let wasm = match u.arbitrary().and_then(|config| {
15
6.58k
        log::debug!("config: {config:#?}");
16
6.58k
        wit_smith::smith(&config, &mut u)
17
6.58k
    }) {
18
        Ok(wasm) => wasm,
19
        Err(_) => return,
20
    };
21
    write_file("doc1.wasm", &wasm);
22
    let (resolve, _pkg) = match wit_component::decode("root", &wasm).unwrap() {
23
        DecodedWasm::WitPackage(resolve, pkg) => (resolve, pkg),
24
        DecodedWasm::Component(..) => unreachable!(),
25
    };
26
    roundtrip_through_printing("doc1", &resolve, &wasm);
27
28
    let (resolve2, pkg2) = match wit_component::decode("root", &wasm).unwrap() {
29
        DecodedWasm::WitPackage(resolve, pkg) => (resolve, pkg),
30
        DecodedWasm::Component(..) => unreachable!(),
31
    };
32
33
    let wasm2 = wit_component::encode(&resolve2, pkg2).expect("failed to encode WIT document");
34
    write_file("doc2.wasm", &wasm2);
35
    roundtrip_through_printing("doc2", &resolve2, &wasm2);
36
37
    if wasm != wasm2 {
38
        panic!("roundtrip wasm didn't match");
39
    }
40
41
    // If there's hundreds or thousands of worlds only work with the first few
42
    // to avoid timing out this fuzzer with asan enabled.
43
    for (id, _world) in resolve.worlds.iter().take(20) {
44
        let mut dummy = wit_component::dummy_module(&resolve, id);
45
        let metadata =
46
            wit_component::metadata::encode(&resolve, id, StringEncoding::UTF8, None).unwrap();
47
        let section = CustomSection {
48
            name: "component-type",
49
            data: &metadata,
50
        };
51
        dummy.push(section.id());
52
        section.encode(&mut dummy);
53
54
        write_file("dummy.wasm", &dummy);
55
        let wasm = wit_component::ComponentEncoder::default()
56
            .module(&dummy)
57
            .unwrap()
58
            .encode()
59
            .unwrap();
60
        write_file("dummy.component.wasm", &wasm);
61
        wasmparser::Validator::new_with_features(wasmparser::WasmFeatures {
62
            component_model: true,
63
            ..Default::default()
64
        })
65
        .validate_all(&wasm)
66
        .unwrap();
67
68
        wit_component::decode("root", &wasm).unwrap();
69
    }
70
});
71
72
12.5k
fn roundtrip_through_printing(file: &str, resolve: &Resolve, wasm: &[u8]) {
73
12.5k
    // For all packages in `resolve` print them all to a string, then re-parse
74
12.5k
    // them and insert them into a `new_resolve`.
75
12.5k
    let mut new_deps = HashMap::new();
76
12.5k
    let mut new_resolve = Resolve::default();
77
12.5k
    let mut last = None;
78
18.0k
    for (_, pkg) in resolve.packages.iter() {
79
18.0k
        let mut map = SourceMap::new();
80
18.0k
        let pkg_name = &pkg.name;
81
46.7k
        for (name, doc) in pkg.documents.iter() {
82
46.7k
            let doc = DocumentPrinter::default().print(resolve, *doc).unwrap();
83
46.7k
            write_file(&format!("{file}-{pkg_name}-{name}.wit"), &doc);
84
46.7k
            map.push(format!("{name}.wit").as_ref(), &name, doc);
85
46.7k
        }
86
18.0k
        let unresolved = map.parse(&pkg.name, pkg.url.as_deref()).unwrap();
87
18.0k
        let id = new_resolve.push(unresolved, &new_deps).unwrap();
88
18.0k
        new_deps.insert(pkg.name.clone(), id);
89
18.0k
        last = Some(id);
90
    }
91
92
    // Finally encode the `new_resolve` which should be the exact same as
93
    // before.
94
12.5k
    let wasm2 = wit_component::encode(&new_resolve, last.unwrap()).unwrap();
95
12.5k
    write_file(&format!("{file}-reencoded.wasm"), &wasm2);
96
12.5k
    if wasm != wasm2 {
97
0
        panic!("failed to roundtrip through text printing");
98
12.5k
    }
99
12.5k
}
100
101
146k
fn write_file(path: &str, contents: impl AsRef<[u8]>) {
102
146k
    if !log::log_enabled!(log::Level::Debug) {
103
146k
        return;
104
0
    }
105
0
    log::debug!("writing file {path}");
106
0
    let contents = contents.as_ref();
107
0
    let path = Path::new(path);
108
0
    std::fs::write(path, contents).unwrap();
109
0
    if path.extension().and_then(|s| s.to_str()) == Some("wasm") {
Unexecuted instantiation: roundtrip_wit::write_file::<&alloc::vec::Vec<u8>>::{closure#0}
Unexecuted instantiation: roundtrip_wit::write_file::<&alloc::string::String>::{closure#0}
110
0
        let path = path.with_extension("wat");
111
0
        log::debug!("writing file {}", path.display());
112
0
        std::fs::write(path, wasmprinter::print_bytes(&contents).unwrap()).unwrap();
113
0
    }
114
146k
}
roundtrip_wit::write_file::<&alloc::vec::Vec<u8>>
Line
Count
Source
101
100k
fn write_file(path: &str, contents: impl AsRef<[u8]>) {
102
100k
    if !log::log_enabled!(log::Level::Debug) {
103
100k
        return;
104
0
    }
105
0
    log::debug!("writing file {path}");
106
0
    let contents = contents.as_ref();
107
0
    let path = Path::new(path);
108
0
    std::fs::write(path, contents).unwrap();
109
0
    if path.extension().and_then(|s| s.to_str()) == Some("wasm") {
110
0
        let path = path.with_extension("wat");
111
0
        log::debug!("writing file {}", path.display());
112
0
        std::fs::write(path, wasmprinter::print_bytes(&contents).unwrap()).unwrap();
113
0
    }
114
100k
}
roundtrip_wit::write_file::<&alloc::string::String>
Line
Count
Source
101
46.7k
fn write_file(path: &str, contents: impl AsRef<[u8]>) {
102
46.7k
    if !log::log_enabled!(log::Level::Debug) {
103
46.7k
        return;
104
0
    }
105
0
    log::debug!("writing file {path}");
106
0
    let contents = contents.as_ref();
107
0
    let path = Path::new(path);
108
0
    std::fs::write(path, contents).unwrap();
109
0
    if path.extension().and_then(|s| s.to_str()) == Some("wasm") {
110
0
        let path = path.with_extension("wat");
111
0
        log::debug!("writing file {}", path.display());
112
0
        std::fs::write(path, wasmprinter::print_bytes(&contents).unwrap()).unwrap();
113
0
    }
114
46.7k
}