1 //! Helper functions to gather information for each of the non-function sections of a
2 //! WebAssembly module.
3 //!
4 //! The code of these helper functions is straightforward since they only read metadata
5 //! about linear memories, tables, globals, etc. and store them for later use.
6 //!
7 //! The special case of the initialize expressions for table elements offsets or global variables
8 //! is handled, according to the semantics of WebAssembly, to only specific expressions that are
9 //! interpreted on the fly.
10 use crate::environ::{Alias, ModuleEnvironment, WasmError, WasmResult};
11 use crate::state::ModuleTranslationState;
12 use crate::translation_utils::{
13     tabletype_to_type, type_to_type, DataIndex, ElemIndex, EntityIndex, EntityType, Event,
14     EventIndex, FuncIndex, Global, GlobalIndex, GlobalInit, InstanceIndex, Memory, MemoryIndex,
15     ModuleIndex, Table, TableElementType, TableIndex, TypeIndex,
16 };
17 use crate::wasm_unsupported;
18 use core::convert::TryFrom;
19 use core::convert::TryInto;
20 use cranelift_codegen::ir::immediates::V128Imm;
21 use cranelift_entity::packed_option::ReservedValue;
22 use cranelift_entity::EntityRef;
23 use std::boxed::Box;
24 use std::vec::Vec;
25 use wasmparser::{
26     self, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, ElementKind,
27     ElementSectionReader, EventSectionReader, EventType, Export, ExportSectionReader, ExternalKind,
28     FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
29     ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, Operator,
30     TableSectionReader, TableType, TypeDef, TypeSectionReader,
31 };
32 
entity_type( ty: ImportSectionEntryType, environ: &mut dyn ModuleEnvironment<'_>, ) -> WasmResult<EntityType>33 fn entity_type(
34     ty: ImportSectionEntryType,
35     environ: &mut dyn ModuleEnvironment<'_>,
36 ) -> WasmResult<EntityType> {
37     Ok(match ty {
38         ImportSectionEntryType::Function(sig) => {
39             EntityType::Function(environ.type_to_signature(TypeIndex::from_u32(sig))?)
40         }
41         ImportSectionEntryType::Module(sig) => {
42             EntityType::Module(environ.type_to_module_type(TypeIndex::from_u32(sig))?)
43         }
44         ImportSectionEntryType::Instance(sig) => {
45             EntityType::Instance(environ.type_to_instance_type(TypeIndex::from_u32(sig))?)
46         }
47         ImportSectionEntryType::Memory(ty) => EntityType::Memory(memory(ty)),
48         ImportSectionEntryType::Event(evt) => EntityType::Event(event(evt)),
49         ImportSectionEntryType::Global(ty) => {
50             EntityType::Global(global(ty, environ, GlobalInit::Import)?)
51         }
52         ImportSectionEntryType::Table(ty) => EntityType::Table(table(ty, environ)?),
53     })
54 }
55 
memory(ty: MemoryType) -> Memory56 fn memory(ty: MemoryType) -> Memory {
57     match ty {
58         MemoryType::M32 { limits, shared } => Memory {
59             minimum: limits.initial,
60             maximum: limits.maximum,
61             shared: shared,
62         },
63         // FIXME(#2361)
64         MemoryType::M64 { .. } => unimplemented!(),
65     }
66 }
67 
event(e: EventType) -> Event68 fn event(e: EventType) -> Event {
69     Event {
70         ty: TypeIndex::from_u32(e.type_index),
71     }
72 }
73 
table(ty: TableType, environ: &mut dyn ModuleEnvironment<'_>) -> WasmResult<Table>74 fn table(ty: TableType, environ: &mut dyn ModuleEnvironment<'_>) -> WasmResult<Table> {
75     Ok(Table {
76         wasm_ty: ty.element_type.try_into()?,
77         ty: match tabletype_to_type(ty.element_type, environ)? {
78             Some(t) => TableElementType::Val(t),
79             None => TableElementType::Func,
80         },
81         minimum: ty.limits.initial,
82         maximum: ty.limits.maximum,
83     })
84 }
85 
global( ty: GlobalType, environ: &mut dyn ModuleEnvironment<'_>, initializer: GlobalInit, ) -> WasmResult<Global>86 fn global(
87     ty: GlobalType,
88     environ: &mut dyn ModuleEnvironment<'_>,
89     initializer: GlobalInit,
90 ) -> WasmResult<Global> {
91     Ok(Global {
92         wasm_ty: ty.content_type.try_into()?,
93         ty: type_to_type(ty.content_type, environ).unwrap(),
94         mutability: ty.mutable,
95         initializer,
96     })
97 }
98 
99 /// Parses the Type section of the wasm module.
parse_type_section<'a>( types: TypeSectionReader<'a>, module_translation_state: &mut ModuleTranslationState, environ: &mut dyn ModuleEnvironment<'a>, ) -> WasmResult<()>100 pub fn parse_type_section<'a>(
101     types: TypeSectionReader<'a>,
102     module_translation_state: &mut ModuleTranslationState,
103     environ: &mut dyn ModuleEnvironment<'a>,
104 ) -> WasmResult<()> {
105     let count = types.get_count();
106     module_translation_state.wasm_types.reserve(count as usize);
107     environ.reserve_types(count)?;
108 
109     for entry in types {
110         match entry? {
111             TypeDef::Func(wasm_func_ty) => {
112                 environ.declare_type_func(wasm_func_ty.clone().try_into()?)?;
113                 module_translation_state
114                     .wasm_types
115                     .push((wasm_func_ty.params, wasm_func_ty.returns));
116             }
117             TypeDef::Module(t) => {
118                 let imports = t
119                     .imports
120                     .iter()
121                     .map(|i| Ok((i.module, i.field, entity_type(i.ty, environ)?)))
122                     .collect::<WasmResult<Vec<_>>>()?;
123                 let exports = t
124                     .exports
125                     .iter()
126                     .map(|e| Ok((e.name, entity_type(e.ty, environ)?)))
127                     .collect::<WasmResult<Vec<_>>>()?;
128                 environ.declare_type_module(&imports, &exports)?;
129             }
130             TypeDef::Instance(t) => {
131                 let exports = t
132                     .exports
133                     .iter()
134                     .map(|e| Ok((e.name, entity_type(e.ty, environ)?)))
135                     .collect::<WasmResult<Vec<_>>>()?;
136                 environ.declare_type_instance(&exports)?;
137             }
138         }
139     }
140     Ok(())
141 }
142 
143 /// Parses the Import section of the wasm module.
parse_import_section<'data>( imports: ImportSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>144 pub fn parse_import_section<'data>(
145     imports: ImportSectionReader<'data>,
146     environ: &mut dyn ModuleEnvironment<'data>,
147 ) -> WasmResult<()> {
148     environ.reserve_imports(imports.get_count())?;
149 
150     for entry in imports {
151         let import = entry?;
152         match import.ty {
153             ImportSectionEntryType::Function(sig) => {
154                 environ.declare_func_import(
155                     TypeIndex::from_u32(sig),
156                     import.module,
157                     import.field,
158                 )?;
159             }
160             ImportSectionEntryType::Module(sig) => {
161                 environ.declare_module_import(
162                     TypeIndex::from_u32(sig),
163                     import.module,
164                     import.field,
165                 )?;
166             }
167             ImportSectionEntryType::Instance(sig) => {
168                 environ.declare_instance_import(
169                     TypeIndex::from_u32(sig),
170                     import.module,
171                     import.field,
172                 )?;
173             }
174             ImportSectionEntryType::Memory(ty) => {
175                 environ.declare_memory_import(memory(ty), import.module, import.field)?;
176             }
177             ImportSectionEntryType::Event(e) => {
178                 environ.declare_event_import(event(e), import.module, import.field)?;
179             }
180             ImportSectionEntryType::Global(ty) => {
181                 let ty = global(ty, environ, GlobalInit::Import)?;
182                 environ.declare_global_import(ty, import.module, import.field)?;
183             }
184             ImportSectionEntryType::Table(ty) => {
185                 let ty = table(ty, environ)?;
186                 environ.declare_table_import(ty, import.module, import.field)?;
187             }
188         }
189     }
190 
191     environ.finish_imports()?;
192     Ok(())
193 }
194 
195 /// Parses the Function section of the wasm module.
parse_function_section( functions: FunctionSectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>196 pub fn parse_function_section(
197     functions: FunctionSectionReader,
198     environ: &mut dyn ModuleEnvironment,
199 ) -> WasmResult<()> {
200     let num_functions = functions.get_count();
201     if num_functions == std::u32::MAX {
202         // We reserve `u32::MAX` for our own use in cranelift-entity.
203         return Err(WasmError::ImplLimitExceeded);
204     }
205 
206     environ.reserve_func_types(num_functions)?;
207 
208     for entry in functions {
209         let sigindex = entry?;
210         environ.declare_func_type(TypeIndex::from_u32(sigindex))?;
211     }
212 
213     Ok(())
214 }
215 
216 /// Parses the Table section of the wasm module.
parse_table_section( tables: TableSectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>217 pub fn parse_table_section(
218     tables: TableSectionReader,
219     environ: &mut dyn ModuleEnvironment,
220 ) -> WasmResult<()> {
221     environ.reserve_tables(tables.get_count())?;
222 
223     for entry in tables {
224         let ty = table(entry?, environ)?;
225         environ.declare_table(ty)?;
226     }
227 
228     Ok(())
229 }
230 
231 /// Parses the Memory section of the wasm module.
parse_memory_section( memories: MemorySectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>232 pub fn parse_memory_section(
233     memories: MemorySectionReader,
234     environ: &mut dyn ModuleEnvironment,
235 ) -> WasmResult<()> {
236     environ.reserve_memories(memories.get_count())?;
237 
238     for entry in memories {
239         let memory = memory(entry?);
240         environ.declare_memory(memory)?;
241     }
242 
243     Ok(())
244 }
245 
246 /// Parses the Event section of the wasm module.
parse_event_section( events: EventSectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>247 pub fn parse_event_section(
248     events: EventSectionReader,
249     environ: &mut dyn ModuleEnvironment,
250 ) -> WasmResult<()> {
251     environ.reserve_events(events.get_count())?;
252 
253     for entry in events {
254         let event = event(entry?);
255         environ.declare_event(event)?;
256     }
257 
258     Ok(())
259 }
260 
261 /// Parses the Global section of the wasm module.
parse_global_section( globals: GlobalSectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>262 pub fn parse_global_section(
263     globals: GlobalSectionReader,
264     environ: &mut dyn ModuleEnvironment,
265 ) -> WasmResult<()> {
266     environ.reserve_globals(globals.get_count())?;
267 
268     for entry in globals {
269         let wasmparser::Global { ty, init_expr } = entry?;
270         let mut init_expr_reader = init_expr.get_binary_reader();
271         let initializer = match init_expr_reader.read_operator()? {
272             Operator::I32Const { value } => GlobalInit::I32Const(value),
273             Operator::I64Const { value } => GlobalInit::I64Const(value),
274             Operator::F32Const { value } => GlobalInit::F32Const(value.bits()),
275             Operator::F64Const { value } => GlobalInit::F64Const(value.bits()),
276             Operator::V128Const { value } => {
277                 GlobalInit::V128Const(V128Imm::from(value.bytes().to_vec().as_slice()))
278             }
279             Operator::RefNull { ty: _ } => GlobalInit::RefNullConst,
280             Operator::RefFunc { function_index } => {
281                 GlobalInit::RefFunc(FuncIndex::from_u32(function_index))
282             }
283             Operator::GlobalGet { global_index } => {
284                 GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index))
285             }
286             ref s => {
287                 return Err(wasm_unsupported!(
288                     "unsupported init expr in global section: {:?}",
289                     s
290                 ));
291             }
292         };
293         let ty = global(ty, environ, initializer)?;
294         environ.declare_global(ty)?;
295     }
296 
297     Ok(())
298 }
299 
300 /// Parses the Export section of the wasm module.
parse_export_section<'data>( exports: ExportSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>301 pub fn parse_export_section<'data>(
302     exports: ExportSectionReader<'data>,
303     environ: &mut dyn ModuleEnvironment<'data>,
304 ) -> WasmResult<()> {
305     environ.reserve_exports(exports.get_count())?;
306 
307     for entry in exports {
308         let Export {
309             field,
310             ref kind,
311             index,
312         } = entry?;
313 
314         // The input has already been validated, so we should be able to
315         // assume valid UTF-8 and use `from_utf8_unchecked` if performance
316         // becomes a concern here.
317         let index = index as usize;
318         match *kind {
319             ExternalKind::Function => environ.declare_func_export(FuncIndex::new(index), field)?,
320             ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), field)?,
321             ExternalKind::Memory => {
322                 environ.declare_memory_export(MemoryIndex::new(index), field)?
323             }
324             ExternalKind::Event => environ.declare_event_export(EventIndex::new(index), field)?,
325             ExternalKind::Global => {
326                 environ.declare_global_export(GlobalIndex::new(index), field)?
327             }
328             ExternalKind::Module => {
329                 environ.declare_module_export(ModuleIndex::new(index), field)?
330             }
331             ExternalKind::Instance => {
332                 environ.declare_instance_export(InstanceIndex::new(index), field)?
333             }
334 
335             // this never gets past validation
336             ExternalKind::Type => unreachable!(),
337         }
338     }
339 
340     environ.finish_exports()?;
341     Ok(())
342 }
343 
344 /// Parses the Start section of the wasm module.
parse_start_section(index: u32, environ: &mut dyn ModuleEnvironment) -> WasmResult<()>345 pub fn parse_start_section(index: u32, environ: &mut dyn ModuleEnvironment) -> WasmResult<()> {
346     environ.declare_start_func(FuncIndex::from_u32(index))?;
347     Ok(())
348 }
349 
read_elems(items: &ElementItems) -> WasmResult<Box<[FuncIndex]>>350 fn read_elems(items: &ElementItems) -> WasmResult<Box<[FuncIndex]>> {
351     let items_reader = items.get_items_reader()?;
352     let mut elems = Vec::with_capacity(usize::try_from(items_reader.get_count()).unwrap());
353     for item in items_reader {
354         let elem = match item? {
355             ElementItem::Null(_ty) => FuncIndex::reserved_value(),
356             ElementItem::Func(index) => FuncIndex::from_u32(index),
357         };
358         elems.push(elem);
359     }
360     Ok(elems.into_boxed_slice())
361 }
362 
363 /// Parses the Element section of the wasm module.
parse_element_section<'data>( elements: ElementSectionReader<'data>, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>364 pub fn parse_element_section<'data>(
365     elements: ElementSectionReader<'data>,
366     environ: &mut dyn ModuleEnvironment,
367 ) -> WasmResult<()> {
368     environ.reserve_table_elements(elements.get_count())?;
369 
370     for (index, entry) in elements.into_iter().enumerate() {
371         let Element { kind, items, ty: _ } = entry?;
372         let segments = read_elems(&items)?;
373         match kind {
374             ElementKind::Active {
375                 table_index,
376                 init_expr,
377             } => {
378                 let mut init_expr_reader = init_expr.get_binary_reader();
379                 let (base, offset) = match init_expr_reader.read_operator()? {
380                     Operator::I32Const { value } => (None, value as u32),
381                     Operator::GlobalGet { global_index } => {
382                         (Some(GlobalIndex::from_u32(global_index)), 0)
383                     }
384                     ref s => {
385                         return Err(wasm_unsupported!(
386                             "unsupported init expr in element section: {:?}",
387                             s
388                         ));
389                     }
390                 };
391                 environ.declare_table_elements(
392                     TableIndex::from_u32(table_index),
393                     base,
394                     offset,
395                     segments,
396                 )?
397             }
398             ElementKind::Passive => {
399                 let index = ElemIndex::from_u32(index as u32);
400                 environ.declare_passive_element(index, segments)?;
401             }
402             ElementKind::Declared => {
403                 environ.declare_elements(segments)?;
404             }
405         }
406     }
407     Ok(())
408 }
409 
410 /// Parses the Data section of the wasm module.
parse_data_section<'data>( data: DataSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>411 pub fn parse_data_section<'data>(
412     data: DataSectionReader<'data>,
413     environ: &mut dyn ModuleEnvironment<'data>,
414 ) -> WasmResult<()> {
415     environ.reserve_data_initializers(data.get_count())?;
416 
417     for (index, entry) in data.into_iter().enumerate() {
418         let Data { kind, data } = entry?;
419         match kind {
420             DataKind::Active {
421                 memory_index,
422                 init_expr,
423             } => {
424                 let mut init_expr_reader = init_expr.get_binary_reader();
425                 let (base, offset) = match init_expr_reader.read_operator()? {
426                     Operator::I32Const { value } => (None, value as u32),
427                     Operator::GlobalGet { global_index } => {
428                         (Some(GlobalIndex::from_u32(global_index)), 0)
429                     }
430                     ref s => {
431                         return Err(wasm_unsupported!(
432                             "unsupported init expr in data section: {:?}",
433                             s
434                         ))
435                     }
436                 };
437                 environ.declare_data_initialization(
438                     MemoryIndex::from_u32(memory_index),
439                     base,
440                     offset,
441                     data,
442                 )?;
443             }
444             DataKind::Passive => {
445                 let index = DataIndex::from_u32(index as u32);
446                 environ.declare_passive_data(index, data)?;
447             }
448         }
449     }
450 
451     Ok(())
452 }
453 
454 /// Parses the Name section of the wasm module.
parse_name_section<'data>( names: NameSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>455 pub fn parse_name_section<'data>(
456     names: NameSectionReader<'data>,
457     environ: &mut dyn ModuleEnvironment<'data>,
458 ) -> WasmResult<()> {
459     for subsection in names {
460         match subsection? {
461             wasmparser::Name::Function(f) => {
462                 let mut names = f.get_map()?;
463                 for _ in 0..names.get_count() {
464                     let Naming { index, name } = names.read()?;
465                     // We reserve `u32::MAX` for our own use in cranelift-entity.
466                     if index != u32::max_value() {
467                         environ.declare_func_name(FuncIndex::from_u32(index), name);
468                     }
469                 }
470             }
471             wasmparser::Name::Module(module) => {
472                 let name = module.get_name()?;
473                 environ.declare_module_name(name);
474             }
475             wasmparser::Name::Local(l) => {
476                 let mut reader = l.get_function_local_reader()?;
477                 for _ in 0..reader.get_count() {
478                     let f = reader.read()?;
479                     if f.func_index == u32::max_value() {
480                         continue;
481                     }
482                     let mut map = f.get_map()?;
483                     for _ in 0..map.get_count() {
484                         let Naming { index, name } = map.read()?;
485                         environ.declare_local_name(FuncIndex::from_u32(f.func_index), index, name)
486                     }
487                 }
488             }
489             wasmparser::Name::Unknown { .. } => {}
490         }
491     }
492     Ok(())
493 }
494 
495 /// Parses the Instance section of the wasm module.
parse_instance_section<'data>( section: wasmparser::InstanceSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>496 pub fn parse_instance_section<'data>(
497     section: wasmparser::InstanceSectionReader<'data>,
498     environ: &mut dyn ModuleEnvironment<'data>,
499 ) -> WasmResult<()> {
500     environ.reserve_instances(section.get_count());
501 
502     for instance in section {
503         let instance = instance?;
504         let module = ModuleIndex::from_u32(instance.module());
505         let args = instance
506             .args()?
507             .into_iter()
508             .map(|arg| {
509                 let arg = arg?;
510                 let index = match arg.kind {
511                     ExternalKind::Function => EntityIndex::Function(FuncIndex::from_u32(arg.index)),
512                     ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(arg.index)),
513                     ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(arg.index)),
514                     ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(arg.index)),
515                     ExternalKind::Module => EntityIndex::Module(ModuleIndex::from_u32(arg.index)),
516                     ExternalKind::Instance => {
517                         EntityIndex::Instance(InstanceIndex::from_u32(arg.index))
518                     }
519                     ExternalKind::Event => unimplemented!(),
520 
521                     // this won't pass validation
522                     ExternalKind::Type => unreachable!(),
523                 };
524                 Ok((arg.name, index))
525             })
526             .collect::<WasmResult<Vec<_>>>()?;
527         environ.declare_instance(module, args)?;
528     }
529     Ok(())
530 }
531 
532 /// Parses the Alias section of the wasm module.
parse_alias_section<'data>( section: wasmparser::AliasSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>533 pub fn parse_alias_section<'data>(
534     section: wasmparser::AliasSectionReader<'data>,
535     environ: &mut dyn ModuleEnvironment<'data>,
536 ) -> WasmResult<()> {
537     for alias in section {
538         let alias = match alias? {
539             wasmparser::Alias::OuterType {
540                 relative_depth,
541                 index,
542             } => Alias::OuterType {
543                 relative_depth,
544                 index: TypeIndex::from_u32(index),
545             },
546             wasmparser::Alias::OuterModule {
547                 relative_depth,
548                 index,
549             } => Alias::OuterModule {
550                 relative_depth,
551                 index: ModuleIndex::from_u32(index),
552             },
553             wasmparser::Alias::InstanceExport {
554                 instance,
555                 export,
556                 kind: _,
557             } => Alias::InstanceExport {
558                 instance: InstanceIndex::from_u32(instance),
559                 export,
560             },
561         };
562         environ.declare_alias(alias)?;
563     }
564     Ok(())
565 }
566