1#![deny(missing_docs)]
8
9use anyhow::{anyhow, bail, Context, Result};
10use std::collections::HashSet;
11use std::mem;
12use wasmparser::{FuncType, ImportSectionEntryType, Payload, TypeDef};
13use wit_parser::*;
14
15pub fn validate(bytes: &[u8]) -> Result<()> {
23 let mut validator = Validator::default();
24 for payload in wasmparser::Parser::new(0).parse_all(bytes) {
25 match payload? {
26 Payload::TypeSection(s) => {
27 validator.validate_section(1, "type", s, |v, ty| {
28 if let TypeDef::Func(ty) = ty {
29 v.core_types.push(ty);
30 }
31 Ok(())
32 })?;
33 }
34 Payload::ImportSection(s) => {
35 validator.validate_section(2, "import", s, |v, ty| {
36 match ty.ty {
37 ImportSectionEntryType::Function(ty) => {
38 v.validate_core_type_idx(ty)?;
39 v.core_funcs.push((ty, CoreFunc::Import));
40 }
41 ImportSectionEntryType::Memory(_) => {
42 v.memories += 1;
43 }
44 _ => {}
45 }
46 Ok(())
47 })?;
48 }
49 Payload::FunctionSection(s) => {
50 validator.validate_section(3, "function", s, |v, ty| {
51 v.validate_core_type_idx(ty)?;
52 v.core_funcs.push((ty, CoreFunc::Local));
53 Ok(())
54 })?;
55 }
56 Payload::MemorySection(s) => {
57 validator.validate_section(4, "memory", s, |v, _| {
58 v.memories += 1;
59 Ok(())
60 })?;
61 }
62 Payload::CustomSection {
63 name: wit_schema_version::SECTION_NAME,
64 data,
65 data_offset,
66 } => {
67 validator
68 .validate_wit_custom_section(data_offset, data)
69 .context("failed to validate interface types section")?;
70 }
71 _ => {}
72 }
73 }
74 Ok(())
75}
76
77#[derive(Default)]
82struct Validator<'a> {
83 visited: bool,
84 last_order: u8,
85 memories: u32,
86 types: Vec<Type>,
87 func: Vec<u32>,
88 exports: HashSet<&'a str>,
89 core_types: Vec<FuncType>,
90 core_funcs: Vec<(u32, CoreFunc)>,
91 type_stack: Vec<ValType>,
92}
93
94enum CoreFunc {
95 Import,
96 Local,
97}
98
99impl<'a> Validator<'a> {
100 fn validate_wit_custom_section(&mut self, offset: usize, bytes: &'a [u8]) -> Result<()> {
106 if self.visited {
107 bail!("found two `wasm-interface-types` custom sections");
108 }
109 self.visited = true;
110
111 let mut parser =
112 Parser::new(offset, bytes).context("failed to parse interface types header")?;
113
114 while !parser.is_empty() {
115 match parser.section().context("failed to read section header")? {
116 Section::Type(s) => {
117 self.validate_section(100, "adapter type", s, Self::validate_type)?
118 }
119 Section::Import(s) => {
120 self.validate_section(101, "adapter import", s, Self::validate_import)?
121 }
122 Section::Func(s) => {
123 self.validate_section(102, "adapter func", s, Self::validate_func)?
124 }
125 Section::Export(s) => {
126 self.validate_section(103, "adapter export", s, Self::validate_export)?
127 }
128 Section::Implement(s) => {
129 self.validate_section(104, "adapter implement", s, Self::validate_implement)?
130 }
131 }
132 }
133 Ok(())
134 }
135
136 fn validate_section<S, T, E>(
137 &mut self,
138 id: u8,
139 name: &str,
140 iter: S,
141 mut validate: impl FnMut(&mut Self, T) -> Result<()>,
142 ) -> Result<()>
143 where
144 S: IntoIterator<Item = Result<T, E>>,
145 E: Into<anyhow::Error>,
146 {
147 if id <= self.last_order {
148 bail!("found `{}` section but was out of order", name);
149 }
150 self.last_order = id;
151 for (i, item) in iter.into_iter().enumerate() {
152 let item = item
153 .map_err(|e| e.into())
154 .with_context(|| format!("failed to parse {} {}", name, i))?;
155 validate(self, item).with_context(|| format!("failed to validate {} {}", name, i))?;
156 }
157 Ok(())
158 }
159
160 fn validate_type(&mut self, ty: Type) -> Result<()> {
161 self.types.push(ty);
162 Ok(())
163 }
164
165 fn validate_import(&mut self, import: Import<'a>) -> Result<()> {
166 self.validate_adapter_type_idx(import.ty)?;
167 self.func.push(import.ty);
168 Ok(())
169 }
170
171 fn validate_func(&mut self, func: Func<'a>) -> Result<()> {
172 let mut type_stack = mem::replace(&mut self.type_stack, Vec::new());
173 self.func.push(func.ty);
174 let ty = self.validate_adapter_type_idx(func.ty)?;
175
176 for instr in func.instrs() {
177 self.validate_instr(instr?, &ty.params, &mut type_stack)?;
178 }
179 for result in ty.results.iter() {
180 self.expect_interface(*result, &mut type_stack)?;
181 }
182 if !type_stack.is_empty() {
183 bail!("value stack isn't empty on function exit");
184 }
185 self.type_stack = type_stack;
186 return Ok(());
187 }
188
189 fn validate_instr(
190 &self,
191 instr: Instruction,
192 params: &[ValType],
193 stack: &mut Vec<ValType>,
194 ) -> Result<()> {
195 use Instruction::*;
196 match instr {
197 ArgGet(idx) => {
198 let ty = params
199 .get(idx as usize)
200 .ok_or_else(|| anyhow!("parameter index out of bounds: {}", idx))?;
201 stack.push(*ty);
202 }
203 CallCore(idx) => {
204 let ty = self.validate_core_func_idx(idx)?.0;
205 for param in ty.params.iter().rev() {
206 self.expect_wasm(*param, stack)?;
207 }
208 for result in ty.returns.iter() {
209 stack.push(wasm2adapter(*result)?);
210 }
211 }
212 MemoryToString(mem) => {
213 if mem >= self.memories {
214 bail!("memory index out of bounds: {}", mem);
215 }
216 self.expect_wasm(wasmparser::Type::I32, stack)?;
217 self.expect_wasm(wasmparser::Type::I32, stack)?;
218 stack.push(ValType::String);
219 }
220 StringToMemory(args) => {
221 if args.mem >= self.memories {
222 bail!("memory index out of bounds: {}", args.mem);
223 }
224 let ty = self.validate_core_func_idx(args.malloc)?.0;
225 if &*ty.params != [wasmparser::Type::I32] || &*ty.returns != [wasmparser::Type::I32]
226 {
227 bail!(
228 "malloc function {} does not have correct signature",
229 args.malloc
230 );
231 }
232 self.expect_interface(ValType::String, stack)?;
233 stack.push(ValType::I32);
234 stack.push(ValType::I32);
235 }
236 CallAdapter(idx) => {
237 let ty = self.validate_adapter_func_idx(idx)?;
238 for param in ty.params.iter().rev() {
239 self.expect_interface(*param, stack)?;
240 }
241 for result in ty.results.iter() {
242 stack.push(*result);
243 }
244 }
245 DeferCallCore(idx) => {
246 let ty = self.validate_core_func_idx(idx)?.0;
247 if ty.returns.len() > 0 {
248 bail!("cannot have returned values in deferred calls");
249 }
250 for param in ty.params.iter() {
252 self.expect_wasm(*param, stack)?;
253 }
254 for param in ty.params.iter().rev() {
256 stack.push(wasm2adapter(*param)?);
257 }
258 }
259 End => bail!("extra `end` instruction found"),
260
261 I32ToS8 => {
262 self.expect_wasm(wasmparser::Type::I32, stack)?;
263 stack.push(ValType::S8);
264 }
265 I32ToS8X => {
266 self.expect_wasm(wasmparser::Type::I32, stack)?;
267 stack.push(ValType::S8);
268 }
269 I32ToU8 => {
270 self.expect_wasm(wasmparser::Type::I32, stack)?;
271 stack.push(ValType::U8);
272 }
273 I32ToS16 => {
274 self.expect_wasm(wasmparser::Type::I32, stack)?;
275 stack.push(ValType::S16);
276 }
277 I32ToS16X => {
278 self.expect_wasm(wasmparser::Type::I32, stack)?;
279 stack.push(ValType::S16);
280 }
281 I32ToU16 => {
282 self.expect_wasm(wasmparser::Type::I32, stack)?;
283 stack.push(ValType::U16);
284 }
285 I32ToS32 => {
286 self.expect_wasm(wasmparser::Type::I32, stack)?;
287 stack.push(ValType::S32);
288 }
289 I32ToU32 => {
290 self.expect_wasm(wasmparser::Type::I32, stack)?;
291 stack.push(ValType::U32);
292 }
293 I32ToS64 => {
294 self.expect_wasm(wasmparser::Type::I32, stack)?;
295 stack.push(ValType::S64);
296 }
297 I32ToU64 => {
298 self.expect_wasm(wasmparser::Type::I32, stack)?;
299 stack.push(ValType::U64);
300 }
301
302 I64ToS8 => {
303 self.expect_wasm(wasmparser::Type::I64, stack)?;
304 stack.push(ValType::S8);
305 }
306 I64ToS8X => {
307 self.expect_wasm(wasmparser::Type::I64, stack)?;
308 stack.push(ValType::S8);
309 }
310 I64ToU8 => {
311 self.expect_wasm(wasmparser::Type::I64, stack)?;
312 stack.push(ValType::U8);
313 }
314 I64ToS16 => {
315 self.expect_wasm(wasmparser::Type::I64, stack)?;
316 stack.push(ValType::S16);
317 }
318 I64ToS16X => {
319 self.expect_wasm(wasmparser::Type::I64, stack)?;
320 stack.push(ValType::S16);
321 }
322 I64ToU16 => {
323 self.expect_wasm(wasmparser::Type::I64, stack)?;
324 stack.push(ValType::U16);
325 }
326 I64ToS32 => {
327 self.expect_wasm(wasmparser::Type::I64, stack)?;
328 stack.push(ValType::S32);
329 }
330 I64ToS32X => {
331 self.expect_wasm(wasmparser::Type::I64, stack)?;
332 stack.push(ValType::S32);
333 }
334 I64ToU32 => {
335 self.expect_wasm(wasmparser::Type::I64, stack)?;
336 stack.push(ValType::U32);
337 }
338 I64ToS64 => {
339 self.expect_wasm(wasmparser::Type::I64, stack)?;
340 stack.push(ValType::S64);
341 }
342 I64ToU64 => {
343 self.expect_wasm(wasmparser::Type::I64, stack)?;
344 stack.push(ValType::U64);
345 }
346
347 S8ToI32 => {
348 self.expect_interface(ValType::S8, stack)?;
349 stack.push(wasm2adapter(wasmparser::Type::I32)?);
350 }
351 U8ToI32 => {
352 self.expect_interface(ValType::U8, stack)?;
353 stack.push(wasm2adapter(wasmparser::Type::I32)?);
354 }
355 S16ToI32 => {
356 self.expect_interface(ValType::S16, stack)?;
357 stack.push(wasm2adapter(wasmparser::Type::I32)?);
358 }
359 U16ToI32 => {
360 self.expect_interface(ValType::U16, stack)?;
361 stack.push(wasm2adapter(wasmparser::Type::I32)?);
362 }
363 S32ToI32 => {
364 self.expect_interface(ValType::S32, stack)?;
365 stack.push(wasm2adapter(wasmparser::Type::I32)?);
366 }
367 U32ToI32 => {
368 self.expect_interface(ValType::U32, stack)?;
369 stack.push(wasm2adapter(wasmparser::Type::I32)?);
370 }
371 S64ToI32 => {
372 self.expect_interface(ValType::S64, stack)?;
373 stack.push(wasm2adapter(wasmparser::Type::I32)?);
374 }
375 S64ToI32X => {
376 self.expect_interface(ValType::S64, stack)?;
377 stack.push(wasm2adapter(wasmparser::Type::I32)?);
378 }
379 U64ToI32 => {
380 self.expect_interface(ValType::U64, stack)?;
381 stack.push(wasm2adapter(wasmparser::Type::I32)?);
382 }
383 U64ToI32X => {
384 self.expect_interface(ValType::U64, stack)?;
385 stack.push(wasm2adapter(wasmparser::Type::I32)?);
386 }
387
388 S8ToI64 => {
389 self.expect_interface(ValType::S8, stack)?;
390 stack.push(wasm2adapter(wasmparser::Type::I64)?);
391 }
392 U8ToI64 => {
393 self.expect_interface(ValType::U8, stack)?;
394 stack.push(wasm2adapter(wasmparser::Type::I64)?);
395 }
396 S16ToI64 => {
397 self.expect_interface(ValType::S16, stack)?;
398 stack.push(wasm2adapter(wasmparser::Type::I64)?);
399 }
400 U16ToI64 => {
401 self.expect_interface(ValType::U16, stack)?;
402 stack.push(wasm2adapter(wasmparser::Type::I64)?);
403 }
404 S32ToI64 => {
405 self.expect_interface(ValType::S32, stack)?;
406 stack.push(wasm2adapter(wasmparser::Type::I64)?);
407 }
408 U32ToI64 => {
409 self.expect_interface(ValType::U32, stack)?;
410 stack.push(wasm2adapter(wasmparser::Type::I64)?);
411 }
412 S64ToI64 => {
413 self.expect_interface(ValType::S64, stack)?;
414 stack.push(wasm2adapter(wasmparser::Type::I64)?);
415 }
416 U64ToI64 => {
417 self.expect_interface(ValType::U64, stack)?;
418 stack.push(wasm2adapter(wasmparser::Type::I64)?);
419 }
420 }
421 Ok(())
422 }
423
424 fn expect_wasm(&self, expected: wasmparser::Type, stack: &mut Vec<ValType>) -> Result<()> {
425 let actual = match stack.pop() {
426 Some(t) => t,
427 None => bail!("expected {:?} on type stack, found nothing", expected),
428 };
429 if !tys_match(actual, expected) {
430 bail!("expected {:?} on type stack, found {:?}", expected, actual);
431 }
432 Ok(())
433 }
434
435 fn expect_interface(&self, expected: ValType, stack: &mut Vec<ValType>) -> Result<()> {
436 let actual = match stack.pop() {
437 Some(t) => t,
438 None => bail!("expected {:?} on type stack, found nothing", expected),
439 };
440 if expected != actual {
441 bail!("expected {:?} on type stack, found {:?}", expected, actual);
442 }
443 Ok(())
444 }
445
446 fn validate_export(&mut self, export: Export<'a>) -> Result<()> {
447 self.validate_adapter_func_idx(export.func)?;
448 if !self.exports.insert(export.name) {
449 bail!("found duplicate export `{}`", export.name);
450 }
451 Ok(())
452 }
453
454 fn validate_implement(&mut self, i: Implement) -> Result<()> {
455 let adapter_ty = self.validate_adapter_func_idx(i.adapter_func)?;
456 let (core_ty, kind) = self.validate_core_func_idx(i.core_func)?;
457 match kind {
458 CoreFunc::Import => {}
459 CoreFunc::Local => {
460 bail!(
461 "implement directive must be connected to imported \
462 function in the core module"
463 );
464 }
465 }
466
467 if adapter_ty.params.len() != core_ty.params.len()
468 || adapter_ty
469 .params
470 .iter()
471 .zip(core_ty.params.iter())
472 .any(|(a, b)| !tys_match(*a, *b))
473 || adapter_ty.results.len() != core_ty.returns.len()
474 || adapter_ty
475 .results
476 .iter()
477 .zip(core_ty.returns.iter())
478 .any(|(a, b)| !tys_match(*a, *b))
479 {
480 bail!(
481 "core function {} has a different type signature \
482 than adapter function {}",
483 i.core_func,
484 i.adapter_func
485 );
486 }
487 Ok(())
488 }
489
490 fn validate_core_type_idx(&self, ty: u32) -> Result<&FuncType> {
491 self.core_types
492 .get(ty as usize)
493 .ok_or_else(|| anyhow!("type index too large: {}", ty))
494 }
495
496 fn validate_adapter_type_idx(&self, ty: u32) -> Result<&Type> {
497 self.types
498 .get(ty as usize)
499 .ok_or_else(|| anyhow!("adapter type index too large: {}", ty))
500 }
501
502 fn validate_adapter_func_idx(&self, ty: u32) -> Result<&Type> {
503 let ty = self
504 .func
505 .get(ty as usize)
506 .ok_or_else(|| anyhow!("adapter func index too large: {}", ty))?;
507 self.validate_adapter_type_idx(*ty)
508 }
509
510 fn validate_core_func_idx(&self, ty: u32) -> Result<(&FuncType, &CoreFunc)> {
511 let (ty, kind) = self
512 .core_funcs
513 .get(ty as usize)
514 .ok_or_else(|| anyhow!("func index too large: {}", ty))?;
515 Ok((self.validate_core_type_idx(*ty)?, kind))
516 }
517}
518
519fn tys_match(a: ValType, b: wasmparser::Type) -> bool {
520 match (a, b) {
521 (ValType::I32, wasmparser::Type::I32)
522 | (ValType::I64, wasmparser::Type::I64)
523 | (ValType::F32, wasmparser::Type::F32)
524 | (ValType::F64, wasmparser::Type::F64)
525 | (ValType::Externref, wasmparser::Type::ExternRef) => true,
526 _ => false,
527 }
528}
529
530fn wasm2adapter(a: wasmparser::Type) -> Result<ValType> {
531 Ok(match a {
532 wasmparser::Type::I32 => ValType::I32,
533 wasmparser::Type::I64 => ValType::I64,
534 wasmparser::Type::F32 => ValType::F32,
535 wasmparser::Type::F64 => ValType::F64,
536 wasmparser::Type::ExternRef => ValType::Externref,
537 _ => bail!("currently {:?} is not a valid wasm interface type", a),
538 })
539}