casper_wasm/elements/
mod.rs

1//! Elements of the WebAssembly binary format.
2
3use crate::io;
4use alloc::{string::String, vec::Vec};
5
6use core::fmt;
7
8macro_rules! buffered_read {
9	($buffer_size: expr, $length: expr, $reader: expr) => {{
10		let mut vec_buf = Vec::new();
11		let mut total_read = 0;
12		let mut buf = [0u8; $buffer_size];
13		while total_read < $length {
14			let next_to_read = if $length - total_read > $buffer_size {
15				$buffer_size
16			} else {
17				$length - total_read
18			};
19			$reader.read(&mut buf[0..next_to_read])?;
20			vec_buf.extend_from_slice(&buf[0..next_to_read]);
21			total_read += next_to_read;
22		}
23		vec_buf
24	}};
25}
26
27mod export_entry;
28mod func;
29mod global_entry;
30mod import_entry;
31mod index_map;
32mod module;
33mod name_section;
34mod ops;
35mod primitives;
36mod reloc_section;
37mod section;
38mod segment;
39mod types;
40
41pub use self::{
42	export_entry::{ExportEntry, Internal},
43	global_entry::GlobalEntry,
44	import_entry::{External, GlobalType, ImportEntry, MemoryType, ResizableLimits, TableType},
45	module::{peek_size, ImportCountType, Module},
46	ops::{opcodes, BrTableData, InitExpr, Instruction, Instructions},
47	primitives::{
48		CountedList, CountedListWriter, CountedWriter, Uint32, Uint64, Uint8, VarInt32, VarInt64,
49		VarInt7, VarUint1, VarUint32, VarUint64, VarUint7,
50	},
51	section::{
52		CodeSection, CustomSection, DataSection, ElementSection, ExportSection, FunctionSection,
53		GlobalSection, ImportSection, MemorySection, Section, TableSection, TypeSection,
54	},
55	types::{BlockType, FunctionType, TableElementType, Type, ValueType},
56};
57
58#[cfg(feature = "atomics")]
59pub use self::ops::AtomicsInstruction;
60
61#[cfg(feature = "simd")]
62pub use self::ops::SimdInstruction;
63
64#[cfg(feature = "sign_ext")]
65pub use self::ops::SignExtInstruction;
66
67#[cfg(feature = "bulk")]
68pub use self::ops::BulkInstruction;
69
70#[cfg(any(feature = "simd", feature = "atomics"))]
71pub use self::ops::MemArg;
72
73pub use self::{
74	func::{Func, FuncBody, Local},
75	index_map::IndexMap,
76	name_section::{
77		FunctionNameSubsection, LocalNameSubsection, ModuleNameSubsection, NameMap, NameSection,
78	},
79	reloc_section::{RelocSection, RelocationEntry},
80	segment::{DataSegment, ElementSegment},
81};
82
83/// Deserialization from serial i/o.
84pub trait Deserialize: Sized {
85	/// Serialization error produced by deserialization routine.
86	type Error: From<io::Error>;
87	/// Deserialize type from serial i/o
88	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
89}
90
91/// Serialization to serial i/o. Takes self by value to consume less memory
92/// (casper-wasm IR is being partially freed by filling the result buffer).
93pub trait Serialize {
94	/// Serialization error produced by serialization routine.
95	type Error: From<io::Error>;
96	/// Serialize type to serial i/o
97	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
98}
99
100/// Deserialization/serialization error
101#[derive(Debug, Clone)]
102pub enum Error {
103	/// Unexpected end of input.
104	UnexpectedEof,
105	/// Invalid magic.
106	InvalidMagic,
107	/// Unsupported version.
108	UnsupportedVersion(u32),
109	/// Inconsistence between declared and actual length.
110	InconsistentLength {
111		/// Expected length of the definition.
112		expected: usize,
113		/// Actual length of the definition.
114		actual: usize,
115	},
116	/// Other static error.
117	Other(&'static str),
118	/// Other allocated error.
119	HeapOther(String),
120	/// Invalid/unknown value type declaration.
121	UnknownValueType(i8),
122	/// Invalid block type declaration.
123	UnknownBlockType(i32),
124	/// Invalid/unknown table element type declaration.
125	UnknownTableElementType(i8),
126	/// Non-utf8 string.
127	NonUtf8String,
128	/// Unknown external kind code.
129	UnknownExternalKind(u8),
130	/// Unknown internal kind code.
131	UnknownInternalKind(u8),
132	/// Unknown opcode encountered.
133	UnknownOpcode(u8),
134	#[cfg(feature = "simd")]
135	/// Unknown SIMD opcode encountered.
136	UnknownSimdOpcode(u32),
137	/// Invalid VarUint1 value.
138	InvalidVarUint1(u8),
139	/// Invalid VarInt32 value.
140	InvalidVarInt32,
141	/// Invalid VarInt64 value.
142	InvalidVarInt64,
143	/// Invalid VarUint32 value.
144	InvalidVarUint32,
145	/// Invalid VarUint64 value.
146	InvalidVarUint64,
147	/// Inconsistent metadata.
148	InconsistentMetadata,
149	/// Invalid section id.
150	InvalidSectionId(u8),
151	/// Sections are out of order.
152	SectionsOutOfOrder,
153	/// Duplicated sections.
154	DuplicatedSections(u8),
155	/// Invalid memory reference (should be 0).
156	InvalidMemoryReference(u8),
157	/// Invalid table reference (should be 0).
158	InvalidTableReference(u8),
159	/// Invalid value used for flags in limits type.
160	InvalidLimitsFlags(u8),
161	/// Unknown function form (should be 0x60).
162	UnknownFunctionForm(u8),
163	/// Invalid varint7 (should be in -64..63 range).
164	InvalidVarInt7(u8),
165	/// Number of function body entries and signatures does not match.
166	InconsistentCode,
167	/// Only flags 0, 1, and 2 are accepted on segments.
168	InvalidSegmentFlags(u32),
169	/// Sum of counts of locals is greater than 2^32.
170	TooManyLocals,
171	/// Duplicated name subsections.
172	DuplicatedNameSubsections(u8),
173	/// Unknown name subsection type.
174	UnknownNameSubsectionType(u8),
175}
176
177impl fmt::Display for Error {
178	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179		match *self {
180			Error::UnexpectedEof => write!(f, "Unexpected end of input"),
181			Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
182			Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
183			Error::InconsistentLength { expected, actual } => {
184				write!(f, "Expected length {}, found {}", expected, actual)
185			},
186			Error::Other(msg) => write!(f, "{}", msg),
187			Error::HeapOther(ref msg) => write!(f, "{}", msg),
188			Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
189			Error::UnknownBlockType(ty) => write!(f, "Invalid or unknown block type {}", ty),
190			Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
191			Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
192			Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
193			Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
194			Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
195			#[cfg(feature = "simd")]
196			Error::UnknownSimdOpcode(opcode) => write!(f, "Unknown SIMD opcode {}", opcode),
197			Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
198			Error::InvalidVarInt7(val) => write!(f, "Not a signed 7-bit integer: {}", val),
199			Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
200			Error::InvalidVarUint32 => write!(f, "Not an unsigned 32-bit integer"),
201			Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
202			Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"),
203			Error::InconsistentMetadata => write!(f, "Inconsistent metadata"),
204			Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id),
205			Error::SectionsOutOfOrder => write!(f, "Sections out of order"),
206			Error::DuplicatedSections(ref id) => write!(f, "Duplicated sections ({})", id),
207			Error::InvalidMemoryReference(ref mem_ref) => {
208				write!(f, "Invalid memory reference ({})", mem_ref)
209			},
210			Error::InvalidTableReference(ref table_ref) => {
211				write!(f, "Invalid table reference ({})", table_ref)
212			},
213			Error::InvalidLimitsFlags(ref flags) => write!(f, "Invalid limits flags ({})", flags),
214			Error::UnknownFunctionForm(ref form) => write!(f, "Unknown function form ({})", form),
215			Error::InconsistentCode => {
216				write!(f, "Number of function body entries and signatures does not match")
217			},
218			Error::InvalidSegmentFlags(n) => write!(f, "Invalid segment flags: {}", n),
219			Error::TooManyLocals => write!(f, "Too many locals"),
220			Error::DuplicatedNameSubsections(n) => write!(f, "Duplicated name subsections: {}", n),
221			Error::UnknownNameSubsectionType(n) => write!(f, "Unknown subsection type: {}", n),
222		}
223	}
224}
225
226#[cfg(feature = "std")]
227impl ::std::error::Error for Error {
228	fn description(&self) -> &str {
229		match *self {
230			Error::UnexpectedEof => "Unexpected end of input",
231			Error::InvalidMagic => "Invalid magic number at start of file",
232			Error::UnsupportedVersion(_) => "Unsupported wasm version",
233			Error::InconsistentLength { .. } => "Inconsistent length",
234			Error::Other(msg) => msg,
235			Error::HeapOther(ref msg) => &msg[..],
236			Error::UnknownValueType(_) => "Invalid or unknown value type",
237			Error::UnknownBlockType(_) => "Invalid or unknown block type",
238			Error::UnknownTableElementType(_) => "Unknown table element type",
239			Error::NonUtf8String => "Non-UTF-8 string",
240			Error::UnknownExternalKind(_) => "Unknown external kind",
241			Error::UnknownInternalKind(_) => "Unknown internal kind",
242			Error::UnknownOpcode(_) => "Unknown opcode",
243			#[cfg(feature = "simd")]
244			Error::UnknownSimdOpcode(_) => "Unknown SIMD opcode",
245			Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
246			Error::InvalidVarInt32 => "Not a signed 32-bit integer",
247			Error::InvalidVarInt7(_) => "Not a signed 7-bit integer",
248			Error::InvalidVarUint32 => "Not an unsigned 32-bit integer",
249			Error::InvalidVarInt64 => "Not a signed 64-bit integer",
250			Error::InvalidVarUint64 => "Not an unsigned 64-bit integer",
251			Error::InconsistentMetadata => "Inconsistent metadata",
252			Error::InvalidSectionId(_) => "Invalid section id",
253			Error::SectionsOutOfOrder => "Sections out of order",
254			Error::DuplicatedSections(_) => "Duplicated section",
255			Error::InvalidMemoryReference(_) => "Invalid memory reference",
256			Error::InvalidTableReference(_) => "Invalid table reference",
257			Error::InvalidLimitsFlags(_) => "Invalid limits flags",
258			Error::UnknownFunctionForm(_) => "Unknown function form",
259			Error::InconsistentCode =>
260				"Number of function body entries and signatures does not match",
261			Error::InvalidSegmentFlags(_) => "Invalid segment flags",
262			Error::TooManyLocals => "Too many locals",
263			Error::DuplicatedNameSubsections(_) => "Duplicated name subsections",
264			Error::UnknownNameSubsectionType(_) => "Unknown name subsections type",
265		}
266	}
267}
268
269impl From<io::Error> for Error {
270	fn from(err: io::Error) -> Self {
271		Error::HeapOther(format!("I/O Error: {:?}", err))
272	}
273}
274
275// These are emitted by section parsers, such as `parse_names` and `parse_reloc`.
276impl From<(Vec<(usize, Error)>, Module)> for Error {
277	fn from(err: (Vec<(usize, Error)>, Module)) -> Self {
278		let ret = err.0.iter().fold(String::new(), |mut acc, item| {
279			acc.push_str(&format!("In section {}: {}\n", item.0, item.1));
280			acc
281		});
282		Error::HeapOther(ret)
283	}
284}
285
286/// Unparsed part of the module/section.
287pub struct Unparsed(pub Vec<u8>);
288
289impl Deserialize for Unparsed {
290	type Error = Error;
291
292	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
293		let len = VarUint32::deserialize(reader)?.into();
294		let mut vec = vec![0u8; len];
295		reader.read(&mut vec[..])?;
296		Ok(Unparsed(vec))
297	}
298}
299
300impl From<Unparsed> for Vec<u8> {
301	fn from(u: Unparsed) -> Vec<u8> {
302		u.0
303	}
304}
305
306/// Deserialize deserializable type from buffer.
307pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> {
308	let mut reader = io::Cursor::new(contents);
309	let result = T::deserialize(&mut reader)?;
310	if reader.position() != contents.len() {
311		// It's a TrailingData, since if there is not enough data then
312		// UnexpectedEof must have been returned earlier in T::deserialize.
313		return Err(io::Error::TrailingData.into());
314	}
315	Ok(result)
316}
317
318/// Create buffer with serialized value.
319pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
320	let mut buf = Vec::new();
321	val.serialize(&mut buf)?;
322	Ok(buf)
323}
324
325/// Deserialize module from the file.
326#[cfg(feature = "std")]
327pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
328	let mut f = ::std::fs::File::open(p)
329		.map_err(|e| Error::HeapOther(format!("Can't read from the file: {:?}", e)))?;
330
331	Module::deserialize(&mut f)
332}
333
334/// Serialize module to the file
335#[cfg(feature = "std")]
336pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error> {
337	let mut io = ::std::fs::File::create(p)
338		.map_err(|e| Error::HeapOther(format!("Can't create the file: {:?}", e)))?;
339
340	module.serialize(&mut io)?;
341	Ok(())
342}