1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(not(feature = "std"))]
4#[macro_use]
5extern crate alloc;
6#[cfg(feature = "std")]
7extern crate std as alloc;
8
9pub mod stack;
10
11pub const DEFAULT_MEMORY_INDEX: u32 = 0;
13pub const DEFAULT_TABLE_INDEX: u32 = 0;
15
16pub const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;
18
19use alloc::{string::String, vec::Vec};
20use core::fmt;
21#[cfg(feature = "std")]
22use std::error;
23
24use self::context::ModuleContextBuilder;
25use parity_wasm::elements::{
26 BlockType,
27 ExportEntry,
28 External,
29 FuncBody,
30 GlobalEntry,
31 GlobalType,
32 InitExpr,
33 Instruction,
34 Internal,
35 MemoryType,
36 Module,
37 ResizableLimits,
38 TableType,
39 Type,
40 ValueType,
41};
42
43pub mod context;
44pub mod func;
45pub mod util;
46
47#[cfg(test)]
48mod tests;
49
50#[derive(Debug)]
53pub struct Error(pub String);
54
55impl fmt::Display for Error {
56 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57 write!(f, "{}", self.0)
58 }
59}
60
61#[cfg(feature = "std")]
62impl error::Error for Error {
63 fn description(&self) -> &str {
64 &self.0
65 }
66}
67
68impl From<stack::Error> for Error {
69 fn from(e: stack::Error) -> Error {
70 Error(format!("Stack: {}", e))
71 }
72}
73
74pub trait Validator {
75 type Input;
77 type Output;
78 type FuncValidator: FuncValidator;
79
80 fn new(module: &Module, input: Self::Input) -> Self;
81
82 fn func_validator_input(&mut self) -> <Self::FuncValidator as FuncValidator>::Input;
83
84 fn on_function_validated(
85 &mut self,
86 index: u32,
87 output: <<Self as Validator>::FuncValidator as FuncValidator>::Output,
88 );
89
90 fn finish(self) -> Self::Output;
91}
92
93pub trait FuncValidator {
94 type Input;
96
97 type Output;
98
99 fn new(ctx: &func::FunctionValidationContext, body: &FuncBody, input: Self::Input) -> Self;
100
101 fn next_instruction(
102 &mut self,
103 ctx: &mut func::FunctionValidationContext,
104 instruction: &Instruction,
105 ) -> Result<(), Error>;
106
107 fn finish(self, ctx: &func::FunctionValidationContext) -> Self::Output;
108}
109
110pub struct PlainValidator;
112
113impl Validator for PlainValidator {
114 type Input = ();
115 type Output = ();
116 type FuncValidator = PlainFuncValidator;
117 fn new(_module: &Module, _args: Self::Input) -> PlainValidator {
118 PlainValidator
119 }
120 fn func_validator_input(&mut self) -> <Self::FuncValidator as FuncValidator>::Input {}
121 fn on_function_validated(
122 &mut self,
123 _index: u32,
124 _output: <<Self as Validator>::FuncValidator as FuncValidator>::Output,
125 ) {
126 }
127 fn finish(self) {}
128}
129
130pub struct PlainFuncValidator;
132
133impl FuncValidator for PlainFuncValidator {
134 type Input = ();
135 type Output = ();
136
137 fn new(
138 _ctx: &func::FunctionValidationContext,
139 _body: &FuncBody,
140 _input: Self::Input,
141 ) -> PlainFuncValidator {
142 PlainFuncValidator
143 }
144
145 fn next_instruction(
146 &mut self,
147 ctx: &mut func::FunctionValidationContext,
148 instruction: &Instruction,
149 ) -> Result<(), Error> {
150 ctx.step(instruction)
151 }
152
153 fn finish(self, _ctx: &func::FunctionValidationContext) {}
154}
155
156pub fn validate_module<V: Validator>(
157 module: &Module,
158 input: <V as Validator>::Input,
159) -> Result<V::Output, Error> {
160 let mut context_builder = ModuleContextBuilder::new();
161 let mut imported_globals = Vec::new();
162 let mut validation = V::new(module, input);
163
164 context_builder.set_types(
166 module
167 .type_section()
168 .map(|ts| {
169 ts.types()
170 .iter()
171 .map(|&Type::Function(ref ty)| ty)
172 .cloned()
173 .collect()
174 })
175 .unwrap_or_default(),
176 );
177
178 for import_entry in module
180 .import_section()
181 .map(|i| i.entries())
182 .unwrap_or_default()
183 {
184 match *import_entry.external() {
185 External::Function(idx) => context_builder.push_func_type_index(idx),
186 External::Table(ref table) => context_builder.push_table(*table),
187 External::Memory(ref memory) => context_builder.push_memory(*memory),
188 External::Global(ref global) => {
189 context_builder.push_global(*global);
190 imported_globals.push(*global);
191 }
192 }
193 }
194
195 if let Some(function_section) = module.function_section() {
197 for func_entry in function_section.entries() {
198 context_builder.push_func_type_index(func_entry.type_ref())
199 }
200 }
201 if let Some(table_section) = module.table_section() {
202 for table_entry in table_section.entries() {
203 validate_table_type(table_entry)?;
204 context_builder.push_table(*table_entry);
205 }
206 }
207 if let Some(mem_section) = module.memory_section() {
208 for mem_entry in mem_section.entries() {
209 validate_memory_type(mem_entry)?;
210 context_builder.push_memory(*mem_entry);
211 }
212 }
213 if let Some(global_section) = module.global_section() {
214 for global_entry in global_section.entries() {
215 validate_global_entry(global_entry, &imported_globals)?;
216 context_builder.push_global(*global_entry.global_type());
217 }
218 }
219
220 let context = context_builder.build();
221
222 let function_section_len = module
223 .function_section()
224 .map(|s| s.entries().len())
225 .unwrap_or(0);
226 let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
227 if function_section_len != code_section_len {
228 return Err(Error(format!(
229 "length of function section is {}, while len of code section is {}",
230 function_section_len, code_section_len
231 )));
232 }
233
234 if function_section_len != 0 {
236 let function_section = module
238 .function_section()
239 .expect("function_section_len != 0; qed");
240 let code_section = module
241 .code_section()
242 .expect("function_section_len != 0; function_section_len == code_section_len; qed");
243 for (index, function) in function_section.entries().iter().enumerate() {
245 let function_body = code_section
246 .bodies()
247 .get(index as usize)
248 .ok_or_else(|| Error(format!("Missing body for function {}", index)))?;
249 let func_validator_input = validation.func_validator_input();
250 let output = func::drive::<V::FuncValidator>(
251 &context,
252 function,
253 function_body,
254 func_validator_input,
255 )
256 .map_err(|Error(ref msg)| {
257 Error(format!(
258 "Function #{} reading/validation error: {}",
259 index, msg
260 ))
261 })?;
262 validation.on_function_validated(index as u32, output);
263 }
264 }
265
266 if let Some(start_fn_idx) = module.start_section() {
268 let (params, return_ty) = context.require_function(start_fn_idx)?;
269 if return_ty != BlockType::NoResult || !params.is_empty() {
270 return Err(Error(
271 "start function expected to have type [] -> []".into(),
272 ));
273 }
274 }
275
276 if let Some(export_section) = module.export_section() {
278 let mut export_names = export_section
279 .entries()
280 .iter()
281 .map(ExportEntry::field)
282 .collect::<Vec<_>>();
283
284 export_names.sort_unstable();
285
286 for (fst, snd) in export_names.iter().zip(export_names.iter().skip(1)) {
287 if fst == snd {
288 return Err(Error(format!("duplicate export {}", fst)));
289 }
290 }
291
292 for export in export_section.entries() {
293 match *export.internal() {
294 Internal::Function(function_index) => {
295 context.require_function(function_index)?;
296 }
297 Internal::Global(global_index) => {
298 context.require_global(global_index, None)?;
299 }
300 Internal::Memory(memory_index) => {
301 context.require_memory(memory_index)?;
302 }
303 Internal::Table(table_index) => {
304 context.require_table(table_index)?;
305 }
306 }
307 }
308 }
309
310 if let Some(import_section) = module.import_section() {
312 for import in import_section.entries() {
313 match *import.external() {
314 External::Function(function_type_index) => {
315 context.require_function_type(function_type_index)?;
316 }
317 External::Global(_) => {}
318 External::Memory(ref memory_type) => {
319 validate_memory_type(memory_type)?;
320 }
321 External::Table(ref table_type) => {
322 validate_table_type(table_type)?;
323 }
324 }
325 }
326 }
327
328 if context.tables().len() > 1 {
330 return Err(Error(format!(
331 "too many tables in index space: {}",
332 context.tables().len()
333 )));
334 }
335
336 if context.memories().len() > 1 {
338 return Err(Error(format!(
339 "too many memory regions in index space: {}",
340 context.memories().len()
341 )));
342 }
343
344 if let Some(data_section) = module.data_section() {
346 for data_segment in data_section.entries() {
347 context.require_memory(data_segment.index())?;
348 let offset = data_segment
349 .offset()
350 .as_ref()
351 .ok_or_else(|| Error("passive memory segments are not supported".into()))?;
352 let init_ty = expr_const_type(offset, context.globals())?;
353 if init_ty != ValueType::I32 {
354 return Err(Error("segment offset should return I32".into()));
355 }
356 }
357 }
358
359 if let Some(element_section) = module.elements_section() {
361 for element_segment in element_section.entries() {
362 context.require_table(element_segment.index())?;
363 let offset = element_segment
364 .offset()
365 .as_ref()
366 .ok_or_else(|| Error("passive element segments are not supported".into()))?;
367 let init_ty = expr_const_type(offset, context.globals())?;
368 if init_ty != ValueType::I32 {
369 return Err(Error("segment offset should return I32".into()));
370 }
371
372 for function_index in element_segment.members() {
373 context.require_function(*function_index)?;
374 }
375 }
376 }
377
378 Ok(validation.finish())
379}
380
381fn validate_limits(limits: &ResizableLimits) -> Result<(), Error> {
382 if let Some(maximum) = limits.maximum() {
383 if limits.initial() > maximum {
384 return Err(Error(format!(
385 "maximum limit {} is less than minimum {}",
386 maximum,
387 limits.initial()
388 )));
389 }
390 }
391 Ok(())
392}
393
394fn validate_memory_type(memory_type: &MemoryType) -> Result<(), Error> {
395 let initial = memory_type.limits().initial();
396 let maximum: Option<u32> = memory_type.limits().maximum();
397 validate_memory(initial, maximum).map_err(Error)
398}
399
400pub fn validate_memory(initial: u32, maximum: Option<u32>) -> Result<(), String> {
401 if initial > LINEAR_MEMORY_MAX_PAGES {
402 return Err(format!(
403 "initial memory size must be at most {} pages",
404 LINEAR_MEMORY_MAX_PAGES
405 ));
406 }
407 if let Some(maximum) = maximum {
408 if initial > maximum {
409 return Err(format!(
410 "maximum limit {} is less than minimum {}",
411 maximum, initial,
412 ));
413 }
414
415 if maximum > LINEAR_MEMORY_MAX_PAGES {
416 return Err(format!(
417 "maximum memory size must be at most {} pages",
418 LINEAR_MEMORY_MAX_PAGES
419 ));
420 }
421 }
422 Ok(())
423}
424
425fn validate_table_type(table_type: &TableType) -> Result<(), Error> {
426 validate_limits(table_type.limits())
427}
428
429fn validate_global_entry(global_entry: &GlobalEntry, globals: &[GlobalType]) -> Result<(), Error> {
430 let init = global_entry.init_expr();
431 let init_expr_ty = expr_const_type(init, globals)?;
432 if init_expr_ty != global_entry.global_type().content_type() {
433 return Err(Error(format!(
434 "Trying to initialize variable of type {:?} with value of type {:?}",
435 global_entry.global_type().content_type(),
436 init_expr_ty
437 )));
438 }
439 Ok(())
440}
441
442fn expr_const_type(init_expr: &InitExpr, globals: &[GlobalType]) -> Result<ValueType, Error> {
444 let code = init_expr.code();
445 if code.len() != 2 {
446 return Err(Error(
447 "Init expression should always be with length 2".into(),
448 ));
449 }
450 let expr_ty: ValueType = match code[0] {
451 Instruction::I32Const(_) => ValueType::I32,
452 Instruction::I64Const(_) => ValueType::I64,
453 Instruction::F32Const(_) => ValueType::F32,
454 Instruction::F64Const(_) => ValueType::F64,
455 Instruction::GetGlobal(idx) => match globals.get(idx as usize) {
456 Some(target_global) => {
457 if target_global.is_mutable() {
458 return Err(Error(format!("Global {} is mutable", idx)));
459 }
460 target_global.content_type()
461 }
462 None => {
463 return Err(Error(format!(
464 "Global {} doesn't exists or not yet defined",
465 idx
466 )));
467 }
468 },
469 _ => return Err(Error("Non constant opcode in init expr".into())),
470 };
471 if code[1] != Instruction::End {
472 return Err(Error("Expression doesn't ends with `end` opcode".into()));
473 }
474 Ok(expr_ty)
475}