concordium_wasm/
artifact_input.rs

1//! Utilities for parsing of artifacts from byte streams.
2
3use crate::{
4    artifact::{
5        Artifact, ArtifactData, ArtifactLocal, ArtifactMemory, ArtifactNamedImport,
6        ArtifactVersion, CompiledFunctionBytes, InstantiatedGlobals, InstantiatedTable,
7    },
8    parse::*,
9    types::{BlockType, FuncIndex, FunctionType, GlobalInit, Name, TypeIndex, ValueType},
10};
11use anyhow::{bail, Context};
12use std::{collections::BTreeMap, io::Cursor};
13
14impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ArtifactLocal {
15    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
16        let multiplicity = cursor.next(ctx)?;
17        let ty = cursor.next(ctx)?;
18        Ok(ArtifactLocal {
19            multiplicity,
20            ty,
21        })
22    }
23}
24
25impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ArtifactNamedImport {
26    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
27        let mod_name = cursor.next(ctx)?;
28        let item_name = cursor.next(ctx)?;
29        let ty = cursor.next(ctx)?;
30        Ok(ArtifactNamedImport {
31            mod_name,
32            item_name,
33            ty,
34        })
35    }
36}
37
38impl<'a, Ctx: Copy> Parseable<'a, Ctx> for InstantiatedGlobals {
39    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
40        let len = u32::parse(ctx, cursor)?;
41        let mut inits = Vec::with_capacity(len as usize);
42        for _ in 0..len {
43            match Byte::parse(ctx, cursor)? {
44                0 => {
45                    inits.push(GlobalInit::I32(cursor.next(ctx)?));
46                }
47                1 => {
48                    inits.push(GlobalInit::I64(cursor.next(ctx)?));
49                }
50                _ => bail!("Unsupported global init tag."),
51            }
52        }
53        Ok(InstantiatedGlobals {
54            inits,
55        })
56    }
57}
58
59impl<'a, Ctx: Copy> Parseable<'a, Ctx> for CompiledFunctionBytes<'a> {
60    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
61        let type_idx = TypeIndex::parse(ctx, cursor).context("Failed to parse type type index.")?;
62        let return_type = BlockType::parse(ctx, cursor).context("Failed to parse return type.")?;
63        let params: &'a [ValueType] =
64            cursor.next(ctx).context("Failed to parse parameter type.")?;
65        let num_locals: u32 = cursor.next(ctx).context("Failed to parse number of locals.")?;
66        let locals: Vec<ArtifactLocal> = cursor.next(ctx).context("Failed to parse locals.")?;
67        let num_registers: u32 = cursor.next(ctx).context("Failed to registers.")?;
68        let constants: Vec<i64> = cursor.next(ctx).context("Failed to parse constants.")?;
69        let code = cursor.next(ctx)?;
70        Ok(CompiledFunctionBytes {
71            type_idx,
72            return_type,
73            params,
74            num_locals,
75            locals,
76            num_registers,
77            constants,
78            code,
79        })
80    }
81}
82
83impl<'a, Ctx: Copy> Parseable<'a, Ctx> for InstantiatedTable {
84    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
85        let functions = cursor.next(ctx)?;
86        Ok(InstantiatedTable {
87            functions,
88        })
89    }
90}
91
92impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ArtifactMemory {
93    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
94        let init_size = cursor.next(ctx)?;
95        let max_size = cursor.next(ctx)?;
96        let init = Vec::<ArtifactData>::parse(ctx, cursor)?;
97        Ok(ArtifactMemory {
98            init_size,
99            max_size,
100            init,
101        })
102    }
103}
104
105impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ArtifactData {
106    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
107        let offset = cursor.next(ctx)?;
108        let init = cursor.next(ctx)?;
109        Ok(Self {
110            offset,
111            init,
112        })
113    }
114}
115
116impl<'a, Ctx> Parseable<'a, Ctx> for ArtifactVersion {
117    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
118        let v: u8 = cursor.next(ctx)?;
119        match v {
120            255 => Ok(Self::V1),
121            n => anyhow::bail!("Unsupported artifact version: {n}."),
122        }
123    }
124}
125
126/// NB: This implementation is only meant to be used on trusted sources.
127/// It optimistically allocates memory, which could lead to problems if the
128/// input is untrusted.
129impl<'a, Ctx: Copy, I: Parseable<'a, Ctx>> Parseable<'a, Ctx>
130    for Artifact<I, CompiledFunctionBytes<'a>>
131{
132    fn parse(ctx: Ctx, cursor: &mut Cursor<&'a [u8]>) -> ParseResult<Self> {
133        let version = cursor.next(ctx)?;
134        let imports: Vec<I> = {
135            let imports_len: u16 = cursor.next(ctx)?;
136            let mut imports = Vec::with_capacity(imports_len.into());
137            for _ in 0..imports_len {
138                imports.push(cursor.next(ctx)?)
139            }
140            imports
141        };
142        let ty: Vec<FunctionType> = Vec::parse(ctx, cursor).context("Failed to parse types.")?;
143        let table = InstantiatedTable::parse(ctx, cursor).context("Failed to parse table.")?;
144        let memory = cursor.next(ctx).context("Failed to parse memory.")?;
145        let global = InstantiatedGlobals::parse(ctx, cursor).context("Failed to parse globals.")?;
146        let export_len = u32::parse(ctx, cursor).context("Failed to parse export_len.")?;
147        let mut export = BTreeMap::new();
148        for _ in 0..export_len {
149            let name = Name::parse(ctx, cursor)?;
150            let idx = FuncIndex::parse(ctx, cursor)?;
151            if export.insert(name, idx).is_some() {
152                bail!("Duplicate names in export list. This should not happen in artifacts.")
153            }
154        }
155        let code = Vec::parse(ctx, cursor).context("Failed to parse code.")?;
156        Ok(Artifact {
157            version,
158            imports,
159            ty,
160            table,
161            memory,
162            global,
163            export,
164            code,
165        })
166    }
167}