wasm_instrument/
export_globals.rs1use alloc::{format, vec::Vec};
2use parity_wasm::elements;
3
4pub fn export_mutable_globals(module: &mut elements::Module, prefix: &str) {
10 let exports = global_section(module)
11 .map(|section| {
12 section
13 .entries()
14 .iter()
15 .enumerate()
16 .filter_map(
17 |(index, global)| {
18 if global.global_type().is_mutable() {
19 Some(index)
20 } else {
21 None
22 }
23 },
24 )
25 .collect::<Vec<_>>()
26 })
27 .unwrap_or_default();
28
29 if module.export_section().is_none() {
30 module
31 .sections_mut()
32 .push(elements::Section::Export(elements::ExportSection::default()));
33 }
34
35 for (symbol_index, export) in exports.into_iter().enumerate() {
36 let new_entry = elements::ExportEntry::new(
37 format!("{}_{}", prefix, symbol_index),
38 elements::Internal::Global(
39 (module.import_count(elements::ImportCountType::Global) + export) as _,
40 ),
41 );
42 export_section(module)
43 .expect("added above if does not exists")
44 .entries_mut()
45 .push(new_entry);
46 }
47}
48
49fn export_section(module: &mut elements::Module) -> Option<&mut elements::ExportSection> {
50 for section in module.sections_mut() {
51 if let elements::Section::Export(sect) = section {
52 return Some(sect)
53 }
54 }
55 None
56}
57
58fn global_section(module: &mut elements::Module) -> Option<&mut elements::GlobalSection> {
59 for section in module.sections_mut() {
60 if let elements::Section::Global(sect) = section {
61 return Some(sect)
62 }
63 }
64 None
65}
66
67#[cfg(test)]
68mod tests {
69
70 use super::export_mutable_globals;
71 use parity_wasm::elements;
72
73 fn parse_wat(source: &str) -> elements::Module {
74 let module_bytes = wat::parse_str(source).unwrap();
75 wasmparser::validate(&module_bytes).unwrap();
76 elements::deserialize_buffer(module_bytes.as_ref()).expect("failed to parse module")
77 }
78
79 macro_rules! test_export_global {
80 (name = $name:ident; input = $input:expr; expected = $expected:expr) => {
81 #[test]
82 fn $name() {
83 let mut input_module = parse_wat($input);
84 let expected_module = parse_wat($expected);
85
86 export_mutable_globals(&mut input_module, "exported_internal_global");
87
88 let actual_bytes = elements::serialize(input_module)
89 .expect("injected module must have a function body");
90
91 let expected_bytes = elements::serialize(expected_module)
92 .expect("injected module must have a function body");
93
94 let actual_wat = wasmprinter::print_bytes(actual_bytes).unwrap();
95 let expected_wat = wasmprinter::print_bytes(expected_bytes).unwrap();
96
97 if actual_wat != expected_wat {
98 for diff in diff::lines(&expected_wat, &actual_wat) {
99 match diff {
100 diff::Result::Left(l) => println!("-{}", l),
101 diff::Result::Both(l, _) => println!(" {}", l),
102 diff::Result::Right(r) => println!("+{}", r),
103 }
104 }
105 panic!()
106 }
107 }
108 };
109 }
110
111 test_export_global! {
112 name = simple;
113 input = r#"
114 (module
115 (global (;0;) (mut i32) (i32.const 1))
116 (global (;1;) (mut i32) (i32.const 0)))
117 "#;
118 expected = r#"
119 (module
120 (global (;0;) (mut i32) (i32.const 1))
121 (global (;1;) (mut i32) (i32.const 0))
122 (export "exported_internal_global_0" (global 0))
123 (export "exported_internal_global_1" (global 1)))
124 "#
125 }
126
127 test_export_global! {
128 name = with_import;
129 input = r#"
130 (module
131 (import "env" "global" (global $global i64))
132 (global (;0;) (mut i32) (i32.const 1))
133 (global (;1;) (mut i32) (i32.const 0)))
134 "#;
135 expected = r#"
136 (module
137 (import "env" "global" (global $global i64))
138 (global (;0;) (mut i32) (i32.const 1))
139 (global (;1;) (mut i32) (i32.const 0))
140 (export "exported_internal_global_0" (global 1))
141 (export "exported_internal_global_1" (global 2)))
142 "#
143 }
144
145 test_export_global! {
146 name = with_import_and_some_are_immutable;
147 input = r#"
148 (module
149 (import "env" "global" (global $global i64))
150 (global (;0;) i32 (i32.const 1))
151 (global (;1;) (mut i32) (i32.const 0)))
152 "#;
153 expected = r#"
154 (module
155 (import "env" "global" (global $global i64))
156 (global (;0;) i32 (i32.const 1))
157 (global (;1;) (mut i32) (i32.const 0))
158 (export "exported_internal_global_0" (global 2)))
159 "#
160 }
161}