summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wasm-smith/tests/exports.rs
blob: ff1dac0cbee0b2eac6f35397ebcdac1cc4475c65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use arbitrary::{Arbitrary, Unstructured};
use rand::{rngs::SmallRng, RngCore, SeedableRng};
use wasm_smith::{Config, Module};
use wasmparser::{
    types::EntityType, CompositeType, FuncType, GlobalType, Parser, Validator, WasmFeatures,
};

mod common;
use common::{parser_features_from_config, validate};

#[derive(Debug, PartialEq)]
enum ExportType {
    Func(FuncType),
    Global(GlobalType),
}

#[test]
fn smoke_test_single_export() {
    let test = r#"
        (module
        	(func (export "foo") (param i32) (result i64)
        		unreachable
        	)
        )
        "#;
    smoke_test_exports(test, 11)
}

#[test]
fn smoke_test_multiple_exports() {
    let test = r#"
        (module
        	(func (export "a") (param i32) (result i64)
        		unreachable
        	)
        	(func (export "b")
        		unreachable
        	)
        	(func (export "c")
        		unreachable
        	)
        )
        "#;
    smoke_test_exports(test, 12)
}

#[test]
fn smoke_test_exported_global() {
    let test = r#"
        (module
        	(func (export "a") (param i32 i32 f32 f64) (result f32)
        		unreachable
        	)
            (global (export "glob") f64 f64.const 0)
        )
        "#;
    smoke_test_exports(test, 20)
}

#[test]
fn smoke_test_export_with_imports() {
    let test = r#"
        (module
            (import "" "foo" (func (param i32)))
            (import "" "bar" (global (mut f32)))
            (func (param i64) unreachable)
            (global i32 (i32.const 0))
            (export "a" (func 0))
            (export "b" (global 0))
            (export "c" (func 1))
            (export "d" (global 1))
        )
            "#;
    smoke_test_exports(test, 21)
}

#[test]
fn smoke_test_with_mutable_global_exports() {
    let test = r#"
        (module
            (global (export "1i32") (mut i32) (i32.const 0))
            (global (export "2i32") (mut i32) (i32.const 0))
            (global (export "1i64") (mut i64) (i64.const 0))
            (global (export "2i64") (mut i64) (i64.const 0))
            (global (export "3i32") (mut i32) (i32.const 0))
            (global (export "3i64") (mut i64) (i64.const 0))
            (global (export "4i32") i32 (i32.const 0))
            (global (export "4i64") i64 (i64.const 0))
        )"#;
    smoke_test_exports(test, 22)
}

fn get_func_and_global_exports(features: WasmFeatures, module: &[u8]) -> Vec<(String, ExportType)> {
    let mut validator = Validator::new_with_features(features);
    let types = validate(&mut validator, module);
    let mut exports = vec![];

    for payload in Parser::new(0).parse_all(module) {
        let payload = payload.unwrap();
        if let wasmparser::Payload::ExportSection(rdr) = payload {
            for export in rdr {
                let export = export.unwrap();
                match types.entity_type_from_export(&export).unwrap() {
                    EntityType::Func(core_id) => {
                        let sub_type = types.get(core_id).expect("Failed to lookup core id");
                        assert!(sub_type.is_final);
                        assert!(sub_type.supertype_idx.is_none());
                        let CompositeType::Func(func_type) = &sub_type.composite_type else {
                            panic!("Expected Func CompositeType, but found {:?}", sub_type);
                        };
                        exports
                            .push((export.name.to_string(), ExportType::Func(func_type.clone())));
                    }
                    EntityType::Global(global_type) => {
                        exports.push((export.name.to_string(), ExportType::Global(global_type)))
                    }
                    other => {
                        panic!("Unexpected entity type {:?}", other)
                    }
                }
            }
        }
    }
    exports
}

fn smoke_test_exports(exports_test_case: &str, seed: u64) {
    let mut rng = SmallRng::seed_from_u64(seed);
    let mut buf = vec![0; 512];
    let wasm = wat::parse_str(exports_test_case).unwrap();
    let expected_exports = get_func_and_global_exports(WasmFeatures::default(), &wasm);

    for _ in 0..1024 {
        rng.fill_bytes(&mut buf);
        let mut u = Unstructured::new(&buf);

        let mut config = Config::arbitrary(&mut u).expect("arbitrary config");
        config.exports = Some(wasm.clone());

        let features = parser_features_from_config(&config);
        let module = Module::new(config, &mut u).unwrap();
        let wasm_bytes = module.to_bytes();

        let generated_exports = get_func_and_global_exports(features, &wasm_bytes);
        assert_eq!(expected_exports, generated_exports);
    }
}