libchisel/
dropsection.rs

1use parity_wasm::elements::{Module, Section};
2
3use super::{ChiselModule, ModuleError, ModuleKind, ModuleTranslator};
4
5/// Enum on which ModuleTranslator is implemented.
6pub enum DropSection {
7    NamesSection,
8    /// Name of the custom section.
9    CustomSectionByName(String),
10    /// Index of the custom section.
11    CustomSectionByIndex(usize),
12    /// Index of the unknown section.
13    UnknownSectionByIndex(usize),
14}
15
16impl<'a> ChiselModule<'a> for DropSection {
17    type ObjectReference = &'a dyn ModuleTranslator;
18
19    fn id(&'a self) -> String {
20        "dropsection".to_string()
21    }
22
23    fn kind(&'a self) -> ModuleKind {
24        ModuleKind::Translator
25    }
26
27    fn as_abstract(&'a self) -> Self::ObjectReference {
28        self as Self::ObjectReference
29    }
30}
31
32// TODO: consider upstreaming this
33fn custom_section_index_for(module: &Module, name: &str) -> Option<usize> {
34    module.sections().iter().position(|e| match e {
35        Section::Custom(_section) => _section.name() == name,
36        Section::Name(_) => name == "name", // If the names section was parsed by parity-wasm, it is distinct from a custom section.
37        _ => false,
38    })
39}
40
41impl DropSection {
42    fn find_index(&self, module: &Module) -> Option<usize> {
43        match &self {
44            DropSection::NamesSection => custom_section_index_for(module, "name"),
45            DropSection::CustomSectionByName(name) => custom_section_index_for(module, &name),
46            DropSection::CustomSectionByIndex(index) => Some(*index),
47            DropSection::UnknownSectionByIndex(index) => Some(*index),
48        }
49    }
50
51    fn drop_section(&self, module: &mut Module) -> Result<bool, ModuleError> {
52        if let Some(index) = self.find_index(&module) {
53            let sections = module.sections_mut();
54            if index < sections.len() {
55                sections.remove(index);
56                return Ok(true);
57            }
58        }
59
60        Ok(false)
61    }
62}
63
64impl<'a> ModuleTranslator for DropSection {
65    fn translate_inplace(&self, module: &mut Module) -> Result<bool, ModuleError> {
66        Ok(self.drop_section(module)?)
67    }
68
69    fn translate(&self, module: &Module) -> Result<Option<Module>, ModuleError> {
70        let mut ret = module.clone();
71        if self.drop_section(&mut ret)? {
72            Ok(Some(ret))
73        } else {
74            Ok(None)
75        }
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use parity_wasm::builder;
82    use parity_wasm::elements::CustomSection;
83    use rustc_hex::FromHex;
84
85    use super::*;
86
87    #[test]
88    fn keep_intact() {
89        let mut module = builder::module().build();
90        let name = "empty".to_string();
91        let dropper = DropSection::CustomSectionByName(name);
92        let did_change = dropper.translate_inplace(&mut module).unwrap();
93        assert_eq!(did_change, false);
94    }
95
96    #[test]
97    fn keep_intact_custom_section() {
98        let mut module = builder::module()
99            .with_section(Section::Custom(CustomSection::new(
100                "test".to_string(),
101                vec![],
102            )))
103            .build();
104        let name = "empty".to_string();
105        let dropper = DropSection::CustomSectionByName(name);
106        let did_change = dropper.translate_inplace(&mut module).unwrap();
107        assert_eq!(did_change, false);
108    }
109
110    #[test]
111    fn remove_custom_section() {
112        let mut module = builder::module()
113            .with_section(Section::Custom(CustomSection::new(
114                "test".to_string(),
115                vec![],
116            )))
117            .build();
118        let name = "test".to_string();
119        let dropper = DropSection::CustomSectionByName(name);
120        let did_change = dropper.translate_inplace(&mut module).unwrap();
121        assert_eq!(did_change, true);
122    }
123
124    #[test]
125    fn remove_custom_section_by_index() {
126        let mut module = builder::module()
127            .with_section(Section::Custom(CustomSection::new(
128                "test".to_string(),
129                vec![],
130            )))
131            .build();
132        let dropper = DropSection::CustomSectionByIndex(0);
133        let did_change = dropper.translate_inplace(&mut module).unwrap();
134        assert_eq!(did_change, true);
135    }
136
137    #[test]
138    fn remove_oob_custom_section_by_index() {
139        let mut module = builder::module()
140            .with_section(Section::Custom(CustomSection::new(
141                "test".to_string(),
142                vec![],
143            )))
144            .build();
145        let dropper = DropSection::CustomSectionByIndex(1);
146        let did_change = dropper.translate_inplace(&mut module).unwrap();
147        assert_eq!(did_change, false);
148    }
149
150    #[test]
151    fn remove_custom_unknown_by_index() {
152        let mut module = builder::module()
153            .with_section(Section::Custom(CustomSection::new(
154                "test".to_string(),
155                vec![],
156            )))
157            .build();
158        let dropper = DropSection::UnknownSectionByIndex(0);
159        let did_change = dropper.translate_inplace(&mut module).unwrap();
160        assert_eq!(did_change, true);
161    }
162
163    #[test]
164    fn remove_oob_unknown_section_by_index() {
165        let mut module = builder::module()
166            .with_section(Section::Custom(CustomSection::new(
167                "test".to_string(),
168                vec![],
169            )))
170            .build();
171        let dropper = DropSection::UnknownSectionByIndex(1);
172        let did_change = dropper.translate_inplace(&mut module).unwrap();
173        assert_eq!(did_change, false);
174    }
175
176    #[test]
177    fn names_section_index() {
178        let input = FromHex::from_hex(
179            "0061736d010000000104016000000303020000070801046d61696e00010a
180            0a020300010b040010000b0014046e616d65010d0200047465737401046d
181            61696e",
182        )
183        .unwrap();
184
185        let mut module = Module::from_bytes(&input).unwrap();
186        assert!(custom_section_index_for(&module, "name").is_some());
187        module = module.parse_names().expect("Should not fail");
188        assert!(custom_section_index_for(&module, "name").is_some());
189    }
190
191    #[test]
192    fn missing_name_section_index() {
193        let input = FromHex::from_hex(
194            "0061736d010000000104016000000303020000070801046d61696e00010a
195            0a020300010b040010000b",
196        )
197        .unwrap();
198
199        let module = Module::from_bytes(&input).unwrap();
200        assert!(custom_section_index_for(&module, "name").is_none());
201    }
202
203    #[test]
204    fn dropped_name_section_parsed() {
205        let input = FromHex::from_hex(
206            "0061736d010000000104016000000303020000070801046d61696e00010a
207            0a020300010b040010000b0014046e616d65010d0200047465737401046d
208            61696e",
209        )
210        .unwrap();
211
212        let mut module = Module::from_bytes(&input)
213            .unwrap()
214            .parse_names()
215            .expect("Should not fail");
216        let mut module1 = module.clone();
217
218        assert!(custom_section_index_for(&module, "name").is_some());
219
220        let dropper = DropSection::CustomSectionByName("name".to_string());
221        let dropper1 = DropSection::NamesSection;
222
223        assert!(dropper
224            .translate_inplace(&mut module)
225            .expect("Should not fail"));
226        assert!(dropper1
227            .translate_inplace(&mut module1)
228            .expect("Should not fail"));
229
230        assert!(custom_section_index_for(&module, "name").is_none());
231        assert!(custom_section_index_for(&module1, "name").is_none());
232    }
233
234    #[test]
235    fn dropped_name_section_index_unparsed() {
236        let input = FromHex::from_hex(
237            "0061736d010000000104016000000303020000070801046d61696e00010a
238            0a020300010b040010000b0014046e616d65010d0200047465737401046d
239            61696e",
240        )
241        .unwrap();
242
243        let mut module = Module::from_bytes(&input).unwrap();
244        let mut module1 = module.clone();
245
246        assert!(custom_section_index_for(&module, "name").is_some());
247
248        let dropper = DropSection::CustomSectionByName("name".to_string());
249        let dropper1 = DropSection::NamesSection;
250
251        assert!(dropper
252            .translate_inplace(&mut module)
253            .expect("Should not fail"));
254        assert!(dropper1
255            .translate_inplace(&mut module1)
256            .expect("Should not fail"));
257
258        assert!(custom_section_index_for(&module, "name").is_none());
259        assert!(custom_section_index_for(&module1, "name").is_none());
260    }
261}