1use crate::{constants::*, types::*, validate::ValidationConfig};
18use anyhow::{bail, ensure};
19use std::{
20 convert::TryFrom,
21 io::{Cursor, Read, Seek, SeekFrom},
22 rc::Rc,
23};
24
25pub type Byte = u8;
27
28#[derive(Debug)]
29pub struct UnparsedSection<'a> {
34 pub(crate) section_id: SectionId,
35 pub(crate) bytes: &'a [u8],
36 len: u64,
40}
41
42#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Copy, Debug)]
43pub enum SectionId {
45 Custom = 0,
46 Type,
47 Import,
48 Function,
49 Table,
50 Memory,
51 Global,
52 Export,
53 Start,
54 Element,
55 Code,
56 Data,
57}
58
59#[derive(Debug)]
60pub struct Skeleton<'a> {
63 pub ty: Option<UnparsedSection<'a>>,
65 pub import: Option<UnparsedSection<'a>>,
67 pub func: Option<UnparsedSection<'a>>,
69 pub table: Option<UnparsedSection<'a>>,
71 pub memory: Option<UnparsedSection<'a>>,
73 pub global: Option<UnparsedSection<'a>>,
75 pub export: Option<UnparsedSection<'a>>,
77 pub start: Option<UnparsedSection<'a>>,
79 pub element: Option<UnparsedSection<'a>>,
81 pub code: Option<UnparsedSection<'a>>,
83 pub data: Option<UnparsedSection<'a>>,
85 pub custom: Vec<UnparsedSection<'a>>,
87}
88
89impl<'a> Skeleton<'a> {
90 pub fn custom_sections_size(&self) -> u64 {
92 self.custom.iter().map(|x| x.len).sum()
95 }
96}
97
98pub type ParseResult<A> = anyhow::Result<A>;
100
101pub trait Parseable<'a, Ctx>: Sized {
108 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self>;
112}
113
114pub(crate) const EMPTY_CTX: () = ();
116
117pub trait GetParseable<A, Ctx> {
126 fn next(self, ctx: Ctx) -> ParseResult<A>;
132}
133
134impl<'a, 'b, Ctx, A: Parseable<'a, Ctx>> GetParseable<A, Ctx> for &'b mut Cursor<&'a [u8]> {
136 #[cfg_attr(not(feature = "fuzz-coverage"), inline(always))]
137 fn next(self, ctx: Ctx) -> ParseResult<A> { A::parse(ctx, self) }
138}
139
140impl<'a, Ctx, A: Parseable<'a, Ctx>> GetParseable<A, Ctx> for &'a [u8] {
144 #[cfg_attr(not(feature = "fuzz-coverage"), inline(always))]
145 fn next(self, ctx: Ctx) -> ParseResult<A> {
146 let mut cursor = Cursor::new(self);
147 let res = A::parse(ctx, &mut cursor)?;
148 ensure!(cursor.position() == self.len() as u64, "Not all of the contents was consumed.");
149 Ok(res)
150 }
151}
152
153impl<'a, Ctx> Parseable<'a, Ctx> for u16 {
155 fn parse(_ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
156 let res = leb128::read::unsigned(&mut cursor.take(3))?;
158 Ok(u16::try_from(res)?)
159 }
160}
161
162impl<'a, Ctx> Parseable<'a, Ctx> for u32 {
164 fn parse(_ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
165 let res = leb128::read::unsigned(&mut cursor.take(5))?;
167 Ok(u32::try_from(res)?)
168 }
169}
170
171impl<'a, Ctx> Parseable<'a, Ctx> for u64 {
173 fn parse(_ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
174 let res = leb128::read::unsigned(&mut cursor.take(10))?;
176 Ok(res)
177 }
178}
179
180impl<'a, Ctx> Parseable<'a, Ctx> for i32 {
182 fn parse(_ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
183 let res = leb128::read::signed(&mut cursor.take(5))?;
185 Ok(i32::try_from(res)?)
186 }
187}
188
189impl<'a, Ctx> Parseable<'a, Ctx> for i64 {
191 fn parse(_ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
192 let res = leb128::read::signed(&mut cursor.take(10))?;
193 Ok(res)
194 }
195}
196
197impl<'a, Ctx> Parseable<'a, Ctx> for SectionId {
199 fn parse(_ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
200 let mut buf = [0u8; 1];
201 cursor.read_exact(&mut buf)?;
202 use SectionId::*;
203 match buf[0] {
204 0 => Ok(Custom),
205 1 => Ok(Type),
206 2 => Ok(Import),
207 3 => Ok(Function),
208 4 => Ok(Table),
209 5 => Ok(Memory),
210 6 => Ok(Global),
211 7 => Ok(Export),
212 8 => Ok(Start),
213 9 => Ok(Element),
214 10 => Ok(Code),
215 11 => Ok(Data),
216 id => bail!("Unknown section id {}", id),
217 }
218 }
219}
220
221impl<'a, Ctx: Copy, A: Parseable<'a, Ctx>> Parseable<'a, Ctx> for Vec<A> {
225 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
226 let len = u32::parse(ctx, cursor)?;
227 let max_initial_capacity =
228 MAX_PREALLOCATED_BYTES / std::cmp::max(1, std::mem::size_of::<A>());
229 let mut out = Vec::with_capacity(std::cmp::min(len as usize, max_initial_capacity));
230 for _ in 0..len {
231 out.push(cursor.next(ctx)?)
232 }
233 Ok(out)
234 }
235}
236
237impl<'a, Ctx> Parseable<'a, Ctx> for &'a [u8] {
240 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
241 let len = u32::parse(ctx, cursor)?;
242 let pos = cursor.position() as usize;
243 let end = pos + len as usize;
244 ensure!(end <= cursor.get_ref().len(), "Malformed byte array");
245 cursor.seek(SeekFrom::Current(i64::from(len)))?;
246 Ok(&cursor.get_ref()[pos..end])
247 }
248}
249
250impl<'a, Ctx: Copy, A: Parseable<'a, Ctx>> Parseable<'a, Ctx> for Option<A> {
252 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
253 match Byte::parse(ctx, cursor)? {
254 0u8 => Ok(None),
255 1u8 => Ok(Some(cursor.next(ctx)?)),
256 tag => bail!("Unsupported option tag: {:#04x}", tag),
257 }
258 }
259}
260
261impl<'a, Ctx> Parseable<'a, Ctx> for &'a [ValueType] {
264 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
265 let len = u32::parse(ctx, cursor)?;
266 let pos = cursor.position() as usize;
267 let end = pos + len as usize;
268 ensure!(end <= cursor.get_ref().len(), "Malformed byte array");
269 cursor.seek(SeekFrom::Current(i64::from(len)))?;
270 let bytes = &cursor.get_ref()[pos..end];
271 for &byte in bytes {
272 if ValueType::try_from(byte).is_err() {
273 bail!(ParseError::UnsupportedValueType {
274 byte
275 })
276 }
277 }
278 Ok(unsafe { &*(bytes as *const [u8] as *const [ValueType]) })
279 }
280}
281
282impl<'a, Ctx: Copy> Parseable<'a, Ctx> for UnparsedSection<'a> {
285 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
286 let start = cursor.position();
287 let section_id = cursor.next(ctx)?;
288 let bytes = cursor.next(ctx)?;
289 let end = cursor.position();
290 let len = end - start;
291 Ok(UnparsedSection {
292 section_id,
293 bytes,
294 len,
295 })
296 }
297}
298
299pub fn parse_skeleton(input: &[u8]) -> ParseResult<Skeleton<'_>> {
307 let cursor = &mut Cursor::new(input);
308 {
309 let mut buf = [0u8; 4];
311 cursor.read_exact(&mut buf)?;
312 ensure!(buf == MAGIC_HASH, "Unknown magic hash");
314 cursor.read_exact(&mut buf)?;
315 ensure!(buf == VERSION, "Unsupported version.");
317 }
318 let mut last_section = SectionId::Custom;
319
320 let mut ty = None;
321 let mut import = None;
322 let mut func = None;
323 let mut table = None;
324 let mut memory = None;
325 let mut global = None;
326 let mut export = None;
327 let mut start = None;
328 let mut element = None;
329 let mut code = None;
330 let mut data = None;
331 let mut custom = Vec::new();
332
333 while cursor.position() < input.len() as u64 {
336 let section = UnparsedSection::parse(EMPTY_CTX, cursor)?;
337 ensure!(
338 section.section_id == SectionId::Custom || section.section_id > last_section,
339 "Section out of place."
340 );
341 if section.section_id != SectionId::Custom {
342 last_section = section.section_id
343 }
344 match section.section_id {
345 SectionId::Custom => custom.push(section),
346 SectionId::Type => ty = Some(section),
347 SectionId::Import => import = Some(section),
348 SectionId::Function => func = Some(section),
349 SectionId::Table => table = Some(section),
350 SectionId::Memory => memory = Some(section),
351 SectionId::Global => global = Some(section),
352 SectionId::Export => export = Some(section),
353 SectionId::Start => start = Some(section),
354 SectionId::Element => element = Some(section),
355 SectionId::Code => code = Some(section),
356 SectionId::Data => data = Some(section),
357 }
358 }
359 ensure!(cursor.position() as usize == input.len(), "Leftover bytes.");
361 Ok(Skeleton {
362 ty,
363 import,
364 func,
365 table,
366 memory,
367 global,
368 export,
369 start,
370 element,
371 code,
372 data,
373 custom,
374 })
375}
376
377impl<'a, Ctx> Parseable<'a, Ctx> for Name {
381 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
382 let name_bytes: &[u8] = cursor.next(ctx)?;
383 ensure!(name_bytes.len() <= MAX_NAME_SIZE, ParseError::NameTooLong);
384 let name = std::str::from_utf8(name_bytes)?.to_string();
385 ensure!(name.is_ascii(), ParseError::OnlyASCIINames);
386 Ok(Name {
387 name,
388 })
389 }
390}
391
392pub fn parse_custom<'a>(sec: &UnparsedSection<'a>) -> ParseResult<CustomSection<'a>> {
394 let mut cursor = Cursor::new(sec.bytes);
395 let name = cursor.next(EMPTY_CTX)?;
396 let contents = &sec.bytes[cursor.position() as usize..];
397 Ok(CustomSection {
398 name,
399 contents,
400 })
401}
402
403impl<'a, Ctx> Parseable<'a, Ctx> for Byte {
405 fn parse(_ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
406 let mut buf = [0u8; 1];
407 cursor.read_exact(&mut buf)?;
408 Ok(buf[0])
409 }
410}
411
412impl<'a, Ctx> Parseable<'a, Ctx> for ValueType {
415 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
416 let byte = Byte::parse(ctx, cursor)?;
417 if let Ok(x) = ValueType::try_from(byte) {
418 Ok(x)
419 } else {
420 bail!(ParseError::UnsupportedValueType {
421 byte
422 })
423 }
424 }
425}
426
427impl<'a, Ctx: Copy> Parseable<'a, Ctx> for Limits {
430 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
431 match Byte::parse(ctx, cursor)? {
432 0x00 => {
433 let min = cursor.next(ctx)?;
434 Ok(Limits {
435 min,
436 max: None,
437 })
438 }
439 0x01 => {
440 let min = cursor.next(ctx)?;
441 let mmax = cursor.next(ctx)?;
442 ensure!(min <= mmax, "Lower limit must be no greater than the upper limit.");
443 Ok(Limits {
444 min,
445 max: Some(mmax),
446 })
447 }
448 tag => bail!("Incorrect limits tag {:#04x}.", tag),
449 }
450 }
451}
452
453fn expect_byte(cursor: &mut Cursor<&[u8]>, byte: Byte) -> ParseResult<()> {
456 let b = Byte::parse(EMPTY_CTX, cursor)?;
457 ensure!(b == byte, "Unexpected byte {:#04x}. Expected {:#04x}", b, byte);
458 Ok(())
459}
460
461impl<'a, Ctx: Copy> Parseable<'a, Ctx> for FunctionType {
464 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
465 expect_byte(cursor, 0x60)?;
466 let parameters = cursor.next(ctx)?;
467 let result_vec = Vec::<ValueType>::parse(ctx, cursor)?;
468 ensure!(result_vec.len() <= 1, ParseError::OnlySingleReturn);
469 let result = result_vec.first().copied();
470 Ok(FunctionType {
471 parameters,
472 result,
473 })
474 }
475}
476
477impl<'a, Ctx: Copy> Parseable<'a, Ctx> for TableType {
482 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
483 expect_byte(cursor, 0x70)?;
484 let limits = Limits::parse(ctx, cursor)?;
485 ensure!(limits.min <= MAX_INIT_TABLE_SIZE, "Initial table size exceeds allowed limits.");
486 Ok(TableType {
487 limits,
488 })
489 }
490}
491
492impl<'a, Ctx: Copy> Parseable<'a, Ctx> for MemoryType {
495 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
496 let limits = Limits::parse(ctx, cursor)?;
497 ensure!(
498 limits.min <= MAX_INIT_MEMORY_SIZE,
499 "Initial memory allocation of {} pages exceeds maximum of {}.",
500 limits.min,
501 MAX_INIT_MEMORY_SIZE
502 );
503 match limits.max {
504 Some(x) => ensure!(x <= 1 << 16, "Memory limits must be in range 2^16."),
505 None => ensure!(limits.min <= 1 << 16, "Memory limits must be in range 2^16."),
506 }
507 Ok(MemoryType {
508 limits,
509 })
510 }
511}
512
513impl<'a, Ctx, X: Parseable<'a, Ctx>> Parseable<'a, Ctx> for Rc<X> {
514 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
515 Ok(Rc::new(X::parse(ctx, cursor)?))
516 }
517}
518
519impl<'a, Ctx: Copy> Parseable<'a, Ctx> for TypeSection {
520 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
521 let types = cursor.next(ctx)?;
522 Ok(TypeSection {
523 types,
524 })
525 }
526}
527
528impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ImportDescription {
529 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
530 match Byte::parse(ctx, cursor)? {
531 0x00 => {
532 let type_idx = cursor.next(ctx)?;
533 Ok(ImportDescription::Func {
534 type_idx,
535 })
536 }
537 tag => bail!(ParseError::UnsupportedImportType {
538 tag
539 }),
540 }
541 }
542}
543
544impl<'a, Ctx: Copy> Parseable<'a, Ctx> for Import {
545 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
546 let mod_name = cursor.next(ctx)?;
547 let item_name = cursor.next(ctx)?;
548 let description = cursor.next(ctx)?;
549 Ok(Import {
550 mod_name,
551 item_name,
552 description,
553 })
554 }
555}
556
557impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ImportSection {
558 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
559 let imports = cursor.next(ctx)?;
560 Ok(ImportSection {
561 imports,
562 })
563 }
564}
565
566impl<'a, Ctx: Copy> Parseable<'a, Ctx> for FunctionSection {
567 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
568 let types = cursor.next(ctx)?;
569 Ok(FunctionSection {
570 types,
571 })
572 }
573}
574
575#[derive(Copy, Clone, Debug)]
576pub(crate) struct InstructionValidationContext<'a> {
586 pub(crate) globals_allowed: Option<&'a GlobalSection>,
589 pub(crate) allow_sign_extension_instr: bool,
591}
592
593fn read_constant_expr(
610 cursor: &mut Cursor<&'_ [u8]>,
611 ty: ValueType,
612 ctx: InstructionValidationContext,
613) -> ParseResult<GlobalInit> {
614 let instr = decode_opcode(ctx.allow_sign_extension_instr, cursor)?;
619 let res = match instr {
620 OpCode::I32Const(n) => {
621 ensure!(ty == ValueType::I32, "Constant instruction of type I64, but I32 expected.");
622 GlobalInit::I32(n)
623 }
624 OpCode::I64Const(n) => {
625 ensure!(ty == ValueType::I64, "Constant instruction of type I32, but I64 expected.");
626 GlobalInit::I64(n)
627 }
628 OpCode::GlobalGet(idx) => match ctx.globals_allowed {
629 None => bail!("GlobalGet not allowed in this constant expression."),
630 Some(globals) => {
631 let global = globals.get(idx).ok_or_else(|| {
632 anyhow::anyhow!("Reference to non-existent global in constant expression.")
633 })?;
634 ensure!(
635 global.init.ty() == ty,
636 "Global in constant expression of incorrect type: {:?} != {:?}",
637 global.init.ty(),
638 ty
639 );
640 ensure!(
641 !global.mutable,
642 "Only references to constant globals can appear in constant expressions."
643 );
644 global.init
645 }
646 },
647 _ => bail!("Not a constant instruction {:?}.", instr),
648 };
649 expect_byte(cursor, END)?;
651 Ok(res)
652}
653
654impl<'a, Ctx: Copy> Parseable<'a, Ctx> for TableSection {
655 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
656 let table_type_vec: Vec<TableType> = cursor.next(ctx)?;
657 ensure!(table_type_vec.len() <= 1, "Only table with index 0 is supported.");
658 Ok(TableSection {
659 table_type: table_type_vec.first().copied(),
660 })
661 }
662}
663
664impl<'a, Ctx: Copy> Parseable<'a, Ctx> for MemorySection {
665 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
666 let memory_types_vec: Vec<MemoryType> = cursor.next(ctx)?;
667 ensure!(memory_types_vec.len() <= 1, "Only memory with index 1 is supported.");
668 Ok(MemorySection {
669 memory_type: memory_types_vec.first().copied(),
670 })
671 }
672}
673
674impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ExportDescription {
675 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
676 match Byte::parse(ctx, cursor)? {
677 0x00 => {
678 let index = FuncIndex::parse(ctx, cursor)?;
679 Ok(ExportDescription::Func {
680 index,
681 })
682 }
683 0x01 => {
684 let index = TableIndex::parse(ctx, cursor)?;
685 ensure!(index == 0, "Only table with index 0 is supported.");
686 Ok(ExportDescription::Table)
687 }
688 0x02 => {
689 let index = MemIndex::parse(ctx, cursor)?;
690 ensure!(index == 0, "Only memory with index 0 is supported.");
691 Ok(ExportDescription::Memory)
692 }
693 0x03 => {
694 let index = GlobalIndex::parse(ctx, cursor)?;
695 Ok(ExportDescription::Global {
696 index,
697 })
698 }
699 byte => bail!("Unsupported export tag {:#04x}.", byte),
700 }
701 }
702}
703
704impl<'a, Ctx: Copy> Parseable<'a, Ctx> for Export {
705 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
706 let name: Name = cursor.next(ctx)?;
707 let description = cursor.next(ctx)?;
708
709 if let ExportDescription::Func {
710 ..
711 } = description
712 {
713 ensure!(
714 name.name.len() <= concordium_contracts_common::constants::MAX_FUNC_NAME_SIZE,
715 ParseError::FuncNameTooLong
716 );
717 }
718
719 Ok(Export {
720 name,
721 description,
722 })
723 }
724}
725
726impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ExportSection {
727 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
728 let exports = cursor.next(ctx)?;
729 Ok(ExportSection {
730 exports,
731 })
732 }
733}
734
735impl<'a, Ctx> Parseable<'a, Ctx> for StartSection {
736 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
737 let _idxs: FuncIndex = cursor.next(ctx)?;
740 bail!(ParseError::StartFunctionsNotSupported);
741 }
742}
743
744impl<'a> Parseable<'a, InstructionValidationContext<'_>> for Element {
745 fn parse(
746 ctx: InstructionValidationContext,
747 cursor: &mut Cursor<&'a [u8]>,
748 ) -> ParseResult<Self> {
749 let table_index = TableIndex::parse(ctx, cursor)?;
750 ensure!(table_index == 0, "Only table index 0 is supported.");
751 let offset = read_constant_expr(cursor, ValueType::I32, ctx)?;
752 let inits = cursor.next(ctx)?;
753 if let GlobalInit::I32(offset) = offset {
754 Ok(Element {
755 offset,
756 inits,
757 })
758 } else {
759 bail!("Internal error, parsed a constant of type I32 that is not an I32.");
760 }
761 }
762}
763
764impl<'a> Parseable<'a, InstructionValidationContext<'_>> for ElementSection {
765 fn parse(
766 ctx: InstructionValidationContext<'_>,
767 cursor: &mut Cursor<&'a [u8]>,
768 ) -> ParseResult<Self> {
769 let elements = cursor.next(ctx)?;
770 Ok(ElementSection {
771 elements,
772 })
773 }
774}
775
776impl<'a> Parseable<'a, ValidationConfig> for Global {
777 fn parse(ctx: ValidationConfig, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
778 let ty = cursor.next(ctx)?;
779 let mutable = match Byte::parse(ctx, cursor)? {
780 0x00 => false,
781 0x01 => true,
782 flag => bail!("Unsupported mutability flag {:#04x}", flag),
783 };
784 let init = read_constant_expr(cursor, ty, InstructionValidationContext {
786 globals_allowed: None,
787 allow_sign_extension_instr: ctx.allow_sign_extension_instr,
788 })?;
789 Ok(Global {
790 init,
791 mutable,
792 })
793 }
794}
795
796impl<'a> Parseable<'a, ValidationConfig> for GlobalSection {
797 fn parse(ctx: ValidationConfig, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
798 let globals = cursor.next(ctx)?;
799 Ok(GlobalSection {
800 globals,
801 })
802 }
803}
804
805const END: Byte = 0x0B;
807
808impl<'a, Ctx> Parseable<'a, Ctx> for BlockType {
811 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
812 match Byte::parse(ctx, cursor)? {
813 0x40 => Ok(BlockType::EmptyType),
814 0x7F => Ok(BlockType::ValueType(ValueType::I32)),
815 0x7E => Ok(BlockType::ValueType(ValueType::I64)),
816 x => bail!("Unsupported block type {}", x),
817 }
818 }
819}
820
821impl<'a, Ctx: Copy> Parseable<'a, Ctx> for MemArg {
822 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
823 let align = cursor.next(ctx)?;
824 let offset = cursor.next(ctx)?;
825 Ok(MemArg {
826 offset,
827 align,
828 })
829 }
830}
831
832impl<'a, Ctx: Copy> Parseable<'a, Ctx> for Local {
833 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
834 let multiplicity = cursor.next(ctx)?;
835 let ty = cursor.next(ctx)?;
836 Ok(Local {
837 multiplicity,
838 ty,
839 })
840 }
841}
842
843impl<'a> Parseable<'a, InstructionValidationContext<'_>> for Data {
850 fn parse(
851 ctx: InstructionValidationContext,
852 cursor: &mut Cursor<&'a [u8]>,
853 ) -> ParseResult<Self> {
854 let index = u32::parse(ctx, cursor)?;
855 ensure!(index == 0, "Only memory index 0 is supported.");
856 let offset = read_constant_expr(cursor, ValueType::I32, ctx)?;
857 let init = cursor.next(ctx)?;
858 if let GlobalInit::I32(offset) = offset {
859 Ok(Data {
860 offset,
861 init,
862 })
863 } else {
864 bail!("Internal error, a constant expression of type I32 is not an I32");
865 }
866 }
867}
868
869impl<'a> Parseable<'a, InstructionValidationContext<'_>> for DataSection {
870 fn parse(
871 ctx: InstructionValidationContext,
872 cursor: &mut Cursor<&'a [u8]>,
873 ) -> ParseResult<Self> {
874 let sections = cursor.next(ctx)?;
875 Ok(DataSection {
876 sections,
877 })
878 }
879}
880
881pub(crate) fn parse_sec_with_default<'a, Ctx, A: Parseable<'a, Ctx> + Default>(
882 ctx: Ctx,
883 sec: &Option<UnparsedSection<'a>>,
884) -> ParseResult<A> {
885 match sec.as_ref() {
886 None => Ok(Default::default()),
887 Some(sec) => sec.bytes.next(ctx),
888 }
889}
890
891#[derive(Debug)]
892pub enum ParseError {
894 UnsupportedInstruction {
895 opcode: Byte,
896 },
897 UnsupportedValueType {
898 byte: Byte,
899 },
900 UnsupportedImportType {
901 tag: Byte,
902 },
903 OnlySingleReturn,
904 OnlyASCIINames,
905 NameTooLong,
906 FuncNameTooLong,
907 StartFunctionsNotSupported,
908}
909
910impl std::fmt::Display for ParseError {
911 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
912 match self {
913 ParseError::UnsupportedInstruction {
914 opcode,
915 } => write!(f, "Unsupported instruction {:#04x}", opcode),
916 ParseError::UnsupportedValueType {
917 byte,
918 } => write!(f, "Unknown value type byte {:#04x}", byte),
919 ParseError::UnsupportedImportType {
920 tag,
921 } => write!(f, "Unsupported import type {:#04x}. Only functions can be imported.", tag),
922 ParseError::OnlySingleReturn => write!(f, "Only single return value is supported."),
923 ParseError::OnlyASCIINames => write!(f, "Only ASCII names are allowed."),
924 ParseError::NameTooLong => write!(f, "Names are limited to {} bytes.", MAX_NAME_SIZE),
925 ParseError::FuncNameTooLong => write!(
926 f,
927 "Names of functions are limited to {} bytes.",
928 concordium_contracts_common::constants::MAX_FUNC_NAME_SIZE
929 ),
930 ParseError::StartFunctionsNotSupported => {
931 write!(f, "Start functions are not supported.")
932 }
933 }
934 }
935}
936
937pub(crate) fn decode_opcode(
939 allow_sign_extension_instr: bool,
940 cursor: &mut Cursor<&[u8]>,
941) -> ParseResult<OpCode> {
942 match Byte::parse(EMPTY_CTX, cursor)? {
943 END => Ok(OpCode::End),
944 0x00 => Ok(OpCode::Unreachable),
945 0x01 => Ok(OpCode::Nop),
946 0x02 => {
947 let bt = cursor.next(EMPTY_CTX)?;
948 Ok(OpCode::Block(bt))
949 }
950 0x03 => {
951 let bt = cursor.next(EMPTY_CTX)?;
952 Ok(OpCode::Loop(bt))
953 }
954 0x04 => {
955 let ty = cursor.next(EMPTY_CTX)?;
956 Ok(OpCode::If {
957 ty,
958 })
959 }
960 0x05 => Ok(OpCode::Else),
961 0x0C => {
962 let l = cursor.next(EMPTY_CTX)?;
963 Ok(OpCode::Br(l))
964 }
965 0x0D => {
966 let l = cursor.next(EMPTY_CTX)?;
967 Ok(OpCode::BrIf(l))
968 }
969 0x0E => {
970 let labels = cursor.next(EMPTY_CTX)?;
971 let default = cursor.next(EMPTY_CTX)?;
972 Ok(OpCode::BrTable {
973 labels,
974 default,
975 })
976 }
977 0x0F => Ok(OpCode::Return),
978 0x10 => {
979 let idx = cursor.next(EMPTY_CTX)?;
980 Ok(OpCode::Call(idx))
981 }
982 0x11 => {
983 let ty = cursor.next(EMPTY_CTX)?;
984 expect_byte(cursor, 0x00)?;
985 Ok(OpCode::CallIndirect(ty))
986 }
987 0x1A => Ok(OpCode::Drop),
989 0x1B => Ok(OpCode::Select),
990 0x20 => {
992 let idx = cursor.next(EMPTY_CTX)?;
993 Ok(OpCode::LocalGet(idx))
994 }
995 0x21 => {
996 let idx = cursor.next(EMPTY_CTX)?;
997 Ok(OpCode::LocalSet(idx))
998 }
999 0x22 => {
1000 let idx = cursor.next(EMPTY_CTX)?;
1001 Ok(OpCode::LocalTee(idx))
1002 }
1003 0x23 => {
1004 let idx = cursor.next(EMPTY_CTX)?;
1005 Ok(OpCode::GlobalGet(idx))
1006 }
1007 0x24 => {
1008 let idx = cursor.next(EMPTY_CTX)?;
1009 Ok(OpCode::GlobalSet(idx))
1010 }
1011 0x28 => {
1013 let memarg = cursor.next(EMPTY_CTX)?;
1014 Ok(OpCode::I32Load(memarg))
1015 }
1016 0x29 => {
1017 let memarg = cursor.next(EMPTY_CTX)?;
1018 Ok(OpCode::I64Load(memarg))
1019 }
1020 0x2C => {
1021 let memarg = cursor.next(EMPTY_CTX)?;
1022 Ok(OpCode::I32Load8S(memarg))
1023 }
1024 0x2D => {
1025 let memarg = cursor.next(EMPTY_CTX)?;
1026 Ok(OpCode::I32Load8U(memarg))
1027 }
1028 0x2E => {
1029 let memarg = cursor.next(EMPTY_CTX)?;
1030 Ok(OpCode::I32Load16S(memarg))
1031 }
1032 0x2F => {
1033 let memarg = cursor.next(EMPTY_CTX)?;
1034 Ok(OpCode::I32Load16U(memarg))
1035 }
1036 0x30 => {
1037 let memarg = cursor.next(EMPTY_CTX)?;
1038 Ok(OpCode::I64Load8S(memarg))
1039 }
1040 0x31 => {
1041 let memarg = cursor.next(EMPTY_CTX)?;
1042 Ok(OpCode::I64Load8U(memarg))
1043 }
1044 0x32 => {
1045 let memarg = cursor.next(EMPTY_CTX)?;
1046 Ok(OpCode::I64Load16S(memarg))
1047 }
1048 0x33 => {
1049 let memarg = cursor.next(EMPTY_CTX)?;
1050 Ok(OpCode::I64Load16U(memarg))
1051 }
1052 0x34 => {
1053 let memarg = cursor.next(EMPTY_CTX)?;
1054 Ok(OpCode::I64Load32S(memarg))
1055 }
1056 0x35 => {
1057 let memarg = cursor.next(EMPTY_CTX)?;
1058 Ok(OpCode::I64Load32U(memarg))
1059 }
1060 0x36 => {
1061 let memarg = cursor.next(EMPTY_CTX)?;
1062 Ok(OpCode::I32Store(memarg))
1063 }
1064 0x37 => {
1065 let memarg = cursor.next(EMPTY_CTX)?;
1066 Ok(OpCode::I64Store(memarg))
1067 }
1068 0x3A => {
1069 let memarg = cursor.next(EMPTY_CTX)?;
1070 Ok(OpCode::I32Store8(memarg))
1071 }
1072 0x3B => {
1073 let memarg = cursor.next(EMPTY_CTX)?;
1074 Ok(OpCode::I32Store16(memarg))
1075 }
1076 0x3C => {
1077 let memarg = cursor.next(EMPTY_CTX)?;
1078 Ok(OpCode::I64Store8(memarg))
1079 }
1080 0x3D => {
1081 let memarg = cursor.next(EMPTY_CTX)?;
1082 Ok(OpCode::I64Store16(memarg))
1083 }
1084 0x3E => {
1085 let memarg = cursor.next(EMPTY_CTX)?;
1086 Ok(OpCode::I64Store32(memarg))
1087 }
1088 0x3F => {
1089 expect_byte(cursor, 0x00)?;
1090 Ok(OpCode::MemorySize)
1091 }
1092 0x40 => {
1093 expect_byte(cursor, 0x00)?;
1094 Ok(OpCode::MemoryGrow)
1095 }
1096 0x41 => {
1098 let n = cursor.next(EMPTY_CTX)?;
1099 Ok(OpCode::I32Const(n))
1100 }
1101 0x42 => {
1102 let n = cursor.next(EMPTY_CTX)?;
1103 Ok(OpCode::I64Const(n))
1104 }
1105 0x45 => Ok(OpCode::I32Eqz),
1107 0x46 => Ok(OpCode::I32Eq),
1108 0x47 => Ok(OpCode::I32Ne),
1109 0x48 => Ok(OpCode::I32LtS),
1110 0x49 => Ok(OpCode::I32LtU),
1111 0x4A => Ok(OpCode::I32GtS),
1112 0x4B => Ok(OpCode::I32GtU),
1113 0x4C => Ok(OpCode::I32LeS),
1114 0x4D => Ok(OpCode::I32LeU),
1115 0x4E => Ok(OpCode::I32GeS),
1116 0x4F => Ok(OpCode::I32GeU),
1117
1118 0x50 => Ok(OpCode::I64Eqz),
1119 0x51 => Ok(OpCode::I64Eq),
1120 0x52 => Ok(OpCode::I64Ne),
1121 0x53 => Ok(OpCode::I64LtS),
1122 0x54 => Ok(OpCode::I64LtU),
1123 0x55 => Ok(OpCode::I64GtS),
1124 0x56 => Ok(OpCode::I64GtU),
1125 0x57 => Ok(OpCode::I64LeS),
1126 0x58 => Ok(OpCode::I64LeU),
1127 0x59 => Ok(OpCode::I64GeS),
1128 0x5A => Ok(OpCode::I64GeU),
1129
1130 0x67 => Ok(OpCode::I32Clz),
1131 0x68 => Ok(OpCode::I32Ctz),
1132 0x69 => Ok(OpCode::I32Popcnt),
1133 0x6A => Ok(OpCode::I32Add),
1134 0x6B => Ok(OpCode::I32Sub),
1135 0x6C => Ok(OpCode::I32Mul),
1136 0x6D => Ok(OpCode::I32DivS),
1137 0x6E => Ok(OpCode::I32DivU),
1138 0x6F => Ok(OpCode::I32RemS),
1139 0x70 => Ok(OpCode::I32RemU),
1140 0x71 => Ok(OpCode::I32And),
1141 0x72 => Ok(OpCode::I32Or),
1142 0x73 => Ok(OpCode::I32Xor),
1143 0x74 => Ok(OpCode::I32Shl),
1144 0x75 => Ok(OpCode::I32ShrS),
1145 0x76 => Ok(OpCode::I32ShrU),
1146 0x77 => Ok(OpCode::I32Rotl),
1147 0x78 => Ok(OpCode::I32Rotr),
1148
1149 0x79 => Ok(OpCode::I64Clz),
1150 0x7A => Ok(OpCode::I64Ctz),
1151 0x7B => Ok(OpCode::I64Popcnt),
1152 0x7C => Ok(OpCode::I64Add),
1153 0x7D => Ok(OpCode::I64Sub),
1154 0x7E => Ok(OpCode::I64Mul),
1155 0x7F => Ok(OpCode::I64DivS),
1156 0x80 => Ok(OpCode::I64DivU),
1157 0x81 => Ok(OpCode::I64RemS),
1158 0x82 => Ok(OpCode::I64RemU),
1159 0x83 => Ok(OpCode::I64And),
1160 0x84 => Ok(OpCode::I64Or),
1161 0x85 => Ok(OpCode::I64Xor),
1162 0x86 => Ok(OpCode::I64Shl),
1163 0x87 => Ok(OpCode::I64ShrS),
1164 0x88 => Ok(OpCode::I64ShrU),
1165 0x89 => Ok(OpCode::I64Rotl),
1166 0x8A => Ok(OpCode::I64Rotr),
1167
1168 0xA7 => Ok(OpCode::I32WrapI64),
1169
1170 0xAC => Ok(OpCode::I64ExtendI32S),
1171 0xAD => Ok(OpCode::I64ExtendI32U),
1172 0xC0 if allow_sign_extension_instr => Ok(OpCode::I32Extend8S),
1173 0xC1 if allow_sign_extension_instr => Ok(OpCode::I32Extend16S),
1174 0xC2 if allow_sign_extension_instr => Ok(OpCode::I64Extend8S),
1175 0xC3 if allow_sign_extension_instr => Ok(OpCode::I64Extend16S),
1176 0xC4 if allow_sign_extension_instr => Ok(OpCode::I64Extend32S),
1177 byte => bail!(ParseError::UnsupportedInstruction {
1178 opcode: byte,
1179 }),
1180 }
1181}
1182
1183pub(crate) struct OpCodeIterator<'a> {
1184 allow_sign_extension_instr: bool,
1185 state: Cursor<&'a [u8]>,
1186}
1187
1188impl<'a> OpCodeIterator<'a> {
1189 pub fn new(allow_sign_extension_instr: bool, bytes: &'a [u8]) -> Self {
1190 Self {
1191 state: Cursor::new(bytes),
1192 allow_sign_extension_instr,
1193 }
1194 }
1195}
1196
1197impl<'a> Iterator for OpCodeIterator<'a> {
1198 type Item = ParseResult<OpCode>;
1199
1200 fn next(&mut self) -> Option<Self::Item> {
1201 if self.state.position() == self.state.get_ref().len() as u64 {
1202 None
1203 } else {
1204 Some(decode_opcode(self.allow_sign_extension_instr, &mut self.state))
1205 }
1206 }
1207}
1208
1209#[derive(Debug)]
1210pub(crate) struct CodeSkeleton<'a> {
1212 pub locals: Vec<Local>,
1214 pub expr_bytes: &'a [u8],
1216}
1217
1218#[derive(Debug, Default)]
1219pub(crate) struct CodeSkeletonSection<'a> {
1223 pub impls: Vec<CodeSkeleton<'a>>,
1224}
1225
1226impl<'a, Ctx: Copy> Parseable<'a, Ctx> for CodeSkeleton<'a> {
1227 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
1228 let size: u32 = cursor.next(ctx)?;
1229 let cur_pos = cursor.position();
1230 let locals = cursor.next(ctx)?;
1231 let end_pos = cursor.position();
1232 ensure!(
1233 u64::from(size) >= end_pos - cur_pos,
1234 "We've already read too many bytes, module is malformed."
1235 );
1236 let remaining = u64::from(size) - (end_pos - cur_pos);
1237 ensure!(
1238 ((end_pos + remaining) as usize) <= cursor.get_ref().len(),
1239 "We would need to read beyond the end of the input."
1240 );
1241 let expr_bytes = &cursor.get_ref()[end_pos as usize..(end_pos + remaining) as usize];
1242 cursor.set_position(end_pos + remaining);
1243 Ok(CodeSkeleton {
1244 locals,
1245 expr_bytes,
1246 })
1247 }
1248}
1249
1250impl<'a, Ctx: Copy> Parseable<'a, Ctx> for CodeSkeletonSection<'a> {
1251 fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
1252 let impls = cursor.next(ctx)?;
1253 Ok(CodeSkeletonSection {
1254 impls,
1255 })
1256 }
1257}