From e59dff527f2e688d49bd5bb8c1d8f8134d0665d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Papierski?= Date: Mon, 3 Feb 2025 16:09:28 +0000 Subject: [PATCH 1/9] Fix formatting --- examples/build.rs | 2 +- examples/data.rs | 2 +- examples/exports.rs | 2 +- examples/info.rs | 2 +- examples/inject.rs | 4 +- examples/roundtrip.rs | 2 +- examples/show.rs | 2 +- src/builder/module.rs | 2 +- src/elements/index_map.rs | 4 +- src/elements/mod.rs | 22 ++++--- src/elements/module.rs | 111 ++++++++++++++++++----------------- src/elements/name_section.rs | 6 +- src/elements/ops.rs | 23 ++++---- src/elements/primitives.rs | 42 ++++++------- src/elements/segment.rs | 4 +- src/elements/types.rs | 4 +- src/io.rs | 2 +- 17 files changed, 121 insertions(+), 115 deletions(-) diff --git a/examples/build.rs b/examples/build.rs index 7520c48..09ec68f 100644 --- a/examples/build.rs +++ b/examples/build.rs @@ -14,7 +14,7 @@ fn main() { let args = env::args().collect::>(); if args.len() != 2 { println!("Usage: {} output_file.wasm", args[0]); - return + return; } // Main entry for the builder api is the module function diff --git a/examples/data.rs b/examples/data.rs index 8ec1db6..bb77605 100644 --- a/examples/data.rs +++ b/examples/data.rs @@ -11,7 +11,7 @@ fn main() { let args = env::args().collect::>(); if args.len() != 2 { println!("Usage: {} somefile.wasm", args[0]); - return + return; } // Here we load module using dedicated for this purpose diff --git a/examples/exports.rs b/examples/exports.rs index 315ea11..955187c 100644 --- a/examples/exports.rs +++ b/examples/exports.rs @@ -48,7 +48,7 @@ fn main() { if args.len() < 2 { println!("Prints export function names with and their types"); println!("Usage: {} ", args[0]); - return + return; } // Here we load module using dedicated for this purpose diff --git a/examples/info.rs b/examples/info.rs index d0618e7..ea3e458 100644 --- a/examples/info.rs +++ b/examples/info.rs @@ -7,7 +7,7 @@ fn main() { let args = env::args().collect::>(); if args.len() != 2 { println!("Usage: {} somefile.wasm", args[0]); - return + return; } let module = casper_wasm::deserialize_file(&args[1]).expect("Failed to load module"); diff --git a/examples/inject.rs b/examples/inject.rs index 8b386ce..a97a2e9 100644 --- a/examples/inject.rs +++ b/examples/inject.rs @@ -16,7 +16,7 @@ pub fn inject_nop(instructions: &mut elements::Instructions) { position += 1; if position >= instructions.len() { - break + break; } } } @@ -25,7 +25,7 @@ fn main() { let args = env::args().collect::>(); if args.len() != 3 { println!("Usage: {} input_file.wasm output_file.wasm", args[0]); - return + return; } let mut module = casper_wasm::deserialize_file(&args[1]).unwrap(); diff --git a/examples/roundtrip.rs b/examples/roundtrip.rs index 21262dd..52f2efe 100644 --- a/examples/roundtrip.rs +++ b/examples/roundtrip.rs @@ -6,7 +6,7 @@ fn main() { let args = env::args().collect::>(); if args.len() != 3 { println!("Usage: {} in.wasm out.wasm", args[0]); - return + return; } let module = match casper_wasm::deserialize_file(&args[1]) diff --git a/examples/show.rs b/examples/show.rs index ddb3af5..36fac77 100644 --- a/examples/show.rs +++ b/examples/show.rs @@ -6,7 +6,7 @@ fn main() { let args = env::args().collect::>(); if args.len() != 3 { println!("Usage: {} ", args[0]); - return + return; } let module = casper_wasm::deserialize_file(&args[1]).expect("Failed to load module"); diff --git a/src/builder/module.rs b/src/builder/module.rs index 48209ab..38e5629 100644 --- a/src/builder/module.rs +++ b/src/builder/module.rs @@ -277,7 +277,7 @@ where let elements::Type::Function(ref existing) = t; *existing == func_type }) { - return existing_entry.0 as u32 + return existing_entry.0 as u32; } self.module.types.types_mut().push(elements::Type::Function(func_type)); self.module.types.types().len() as u32 - 1 diff --git a/src/elements/index_map.rs b/src/elements/index_map.rs index 946d6fd..3812fe4 100644 --- a/src/elements/index_map.rs +++ b/src/elements/index_map.rs @@ -107,13 +107,13 @@ impl IndexMap { for _ in 0..len { let idx: u32 = VarUint32::deserialize(rdr)?.into(); if idx as usize >= max_entry_space { - return Err(Error::Other("index is larger than expected")) + return Err(Error::Other("index is larger than expected")); } match prev_idx { Some(prev) if prev >= idx => { // Supposedly these names must be "sorted by index", so // let's try enforcing that and seeing what happens. - return Err(Error::Other("indices are out of order")) + return Err(Error::Other("indices are out of order")); }, _ => { prev_idx = Some(idx); diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 822814e..c076d87 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -204,14 +204,17 @@ impl fmt::Display for Error { Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), Error::SectionsOutOfOrder => write!(f, "Sections out of order"), Error::DuplicatedSections(ref id) => write!(f, "Duplicated sections ({})", id), - Error::InvalidMemoryReference(ref mem_ref) => - write!(f, "Invalid memory reference ({})", mem_ref), - Error::InvalidTableReference(ref table_ref) => - write!(f, "Invalid table reference ({})", table_ref), + Error::InvalidMemoryReference(ref mem_ref) => { + write!(f, "Invalid memory reference ({})", mem_ref) + }, + Error::InvalidTableReference(ref table_ref) => { + write!(f, "Invalid table reference ({})", table_ref) + }, Error::InvalidLimitsFlags(ref flags) => write!(f, "Invalid limits flags ({})", flags), Error::UnknownFunctionForm(ref form) => write!(f, "Unknown function form ({})", form), - Error::InconsistentCode => - write!(f, "Number of function body entries and signatures does not match"), + Error::InconsistentCode => { + write!(f, "Number of function body entries and signatures does not match") + }, Error::InvalidSegmentFlags(n) => write!(f, "Invalid segment flags: {}", n), Error::TooManyLocals => write!(f, "Too many locals"), Error::DuplicatedNameSubsections(n) => write!(f, "Duplicated name subsections: {}", n), @@ -253,8 +256,9 @@ impl ::std::error::Error for Error { Error::InvalidTableReference(_) => "Invalid table reference", Error::InvalidLimitsFlags(_) => "Invalid limits flags", Error::UnknownFunctionForm(_) => "Unknown function form", - Error::InconsistentCode => - "Number of function body entries and signatures does not match", + Error::InconsistentCode => { + "Number of function body entries and signatures does not match" + }, Error::InvalidSegmentFlags(_) => "Invalid segment flags", Error::TooManyLocals => "Too many locals", Error::DuplicatedNameSubsections(_) => "Duplicated name subsections", @@ -307,7 +311,7 @@ pub fn deserialize_buffer(contents: &[u8]) -> Result Option<&CodeSection> { for section in self.sections() { if let Section::Code(ref code_section) = *section { - return Some(code_section) + return Some(code_section); } } None @@ -127,7 +127,7 @@ impl Module { pub fn code_section_mut(&mut self) -> Option<&mut CodeSection> { for section in self.sections_mut() { if let Section::Code(ref mut code_section) = *section { - return Some(code_section) + return Some(code_section); } } None @@ -137,7 +137,7 @@ impl Module { pub fn type_section(&self) -> Option<&TypeSection> { for section in self.sections() { if let Section::Type(ref type_section) = *section { - return Some(type_section) + return Some(type_section); } } None @@ -147,7 +147,7 @@ impl Module { pub fn type_section_mut(&mut self) -> Option<&mut TypeSection> { for section in self.sections_mut() { if let Section::Type(ref mut type_section) = *section { - return Some(type_section) + return Some(type_section); } } None @@ -157,7 +157,7 @@ impl Module { pub fn import_section(&self) -> Option<&ImportSection> { for section in self.sections() { if let Section::Import(ref import_section) = *section { - return Some(import_section) + return Some(import_section); } } None @@ -167,7 +167,7 @@ impl Module { pub fn import_section_mut(&mut self) -> Option<&mut ImportSection> { for section in self.sections_mut() { if let Section::Import(ref mut import_section) = *section { - return Some(import_section) + return Some(import_section); } } None @@ -177,7 +177,7 @@ impl Module { pub fn global_section(&self) -> Option<&GlobalSection> { for section in self.sections() { if let Section::Global(ref section) = *section { - return Some(section) + return Some(section); } } None @@ -187,7 +187,7 @@ impl Module { pub fn global_section_mut(&mut self) -> Option<&mut GlobalSection> { for section in self.sections_mut() { if let Section::Global(ref mut section) = *section { - return Some(section) + return Some(section); } } None @@ -197,7 +197,7 @@ impl Module { pub fn export_section(&self) -> Option<&ExportSection> { for section in self.sections() { if let Section::Export(ref export_section) = *section { - return Some(export_section) + return Some(export_section); } } None @@ -207,7 +207,7 @@ impl Module { pub fn export_section_mut(&mut self) -> Option<&mut ExportSection> { for section in self.sections_mut() { if let Section::Export(ref mut export_section) = *section { - return Some(export_section) + return Some(export_section); } } None @@ -217,7 +217,7 @@ impl Module { pub fn table_section(&self) -> Option<&TableSection> { for section in self.sections() { if let Section::Table(ref section) = *section { - return Some(section) + return Some(section); } } None @@ -227,7 +227,7 @@ impl Module { pub fn table_section_mut(&mut self) -> Option<&mut TableSection> { for section in self.sections_mut() { if let Section::Table(ref mut section) = *section { - return Some(section) + return Some(section); } } None @@ -237,7 +237,7 @@ impl Module { pub fn data_section(&self) -> Option<&DataSection> { for section in self.sections() { if let Section::Data(ref section) = *section { - return Some(section) + return Some(section); } } None @@ -247,7 +247,7 @@ impl Module { pub fn data_section_mut(&mut self) -> Option<&mut DataSection> { for section in self.sections_mut() { if let Section::Data(ref mut section) = *section { - return Some(section) + return Some(section); } } None @@ -257,7 +257,7 @@ impl Module { pub fn elements_section(&self) -> Option<&ElementSection> { for section in self.sections() { if let Section::Element(ref section) = *section { - return Some(section) + return Some(section); } } None @@ -267,7 +267,7 @@ impl Module { pub fn elements_section_mut(&mut self) -> Option<&mut ElementSection> { for section in self.sections_mut() { if let Section::Element(ref mut section) = *section { - return Some(section) + return Some(section); } } None @@ -277,7 +277,7 @@ impl Module { pub fn memory_section(&self) -> Option<&MemorySection> { for section in self.sections() { if let Section::Memory(ref section) = *section { - return Some(section) + return Some(section); } } None @@ -287,7 +287,7 @@ impl Module { pub fn memory_section_mut(&mut self) -> Option<&mut MemorySection> { for section in self.sections_mut() { if let Section::Memory(ref mut section) = *section { - return Some(section) + return Some(section); } } None @@ -297,7 +297,7 @@ impl Module { pub fn function_section(&self) -> Option<&FunctionSection> { for section in self.sections() { if let Section::Function(ref sect) = *section { - return Some(sect) + return Some(sect); } } None @@ -307,7 +307,7 @@ impl Module { pub fn function_section_mut(&mut self) -> Option<&mut FunctionSection> { for section in self.sections_mut() { if let Section::Function(ref mut sect) = *section { - return Some(sect) + return Some(sect); } } None @@ -317,7 +317,7 @@ impl Module { pub fn start_section(&self) -> Option { for section in self.sections() { if let Section::Start(sect) = *section { - return Some(sect) + return Some(sect); } } None @@ -328,7 +328,7 @@ impl Module { for section in self.sections_mut().iter_mut() { if let Section::Start(_sect) = *section { *section = Section::Start(new_start); - return + return; } } // This should not fail, because we update the existing section above. @@ -343,7 +343,7 @@ impl Module { for (index, section) in sections.iter_mut().enumerate() { if let Section::Start(_sect) = section { rmidx = index; - break + break; } } if rmidx < sections.len() { @@ -366,7 +366,7 @@ impl Module { if let Section::Custom(ref mut sect) = *section { if sect.name() == name { *sect = CustomSection::new(name, payload); - return + return; } } } @@ -422,7 +422,7 @@ impl Module { pub fn names_section(&self) -> Option<&NameSection> { for section in self.sections() { if let Section::Name(ref sect) = *section { - return Some(sect) + return Some(sect); } } None @@ -435,7 +435,7 @@ impl Module { pub fn names_section_mut(&mut self) -> Option<&mut NameSection> { for section in self.sections_mut() { if let Section::Name(ref mut sect) = *section { - return Some(sect) + return Some(sect); } } None @@ -460,7 +460,7 @@ impl Module { Ok(ns) => ns, Err(e) => { parse_errors.push((i, e)); - continue + continue; }, }; Some(name_section) @@ -502,12 +502,12 @@ impl Module { Ok(reloc_section) => reloc_section, Err(e) => { parse_errors.push((i, e)); - continue + continue; }, }; if rdr.position() != custom.payload().len() { parse_errors.push((i, io::Error::InvalidData.into())); - continue + continue; } Some(Section::Reloc(reloc_section)) } else { @@ -537,10 +537,10 @@ impl Module { .filter(|import| { matches!( (count_type, *import.external()), - (ImportCountType::Function, External::Function(_)) | - (ImportCountType::Global, External::Global(_)) | - (ImportCountType::Table, External::Table(_)) | - (ImportCountType::Memory, External::Memory(_)) + (ImportCountType::Function, External::Function(_)) + | (ImportCountType::Global, External::Global(_)) + | (ImportCountType::Table, External::Table(_)) + | (ImportCountType::Memory, External::Memory(_)) ) }) .count() @@ -550,26 +550,26 @@ impl Module { /// Query functions space. pub fn functions_space(&self) -> usize { - self.import_count(ImportCountType::Function) + - self.function_section().map(|fs| fs.entries().len()).unwrap_or(0) + self.import_count(ImportCountType::Function) + + self.function_section().map(|fs| fs.entries().len()).unwrap_or(0) } /// Query globals space. pub fn globals_space(&self) -> usize { - self.import_count(ImportCountType::Global) + - self.global_section().map(|gs| gs.entries().len()).unwrap_or(0) + self.import_count(ImportCountType::Global) + + self.global_section().map(|gs| gs.entries().len()).unwrap_or(0) } /// Query table space. pub fn table_space(&self) -> usize { - self.import_count(ImportCountType::Table) + - self.table_section().map(|ts| ts.entries().len()).unwrap_or(0) + self.import_count(ImportCountType::Table) + + self.table_section().map(|ts| ts.entries().len()).unwrap_or(0) } /// Query memory space. pub fn memory_space(&self) -> usize { - self.import_count(ImportCountType::Memory) + - self.memory_section().map(|ms| ms.entries().len()).unwrap_or(0) + self.import_count(ImportCountType::Memory) + + self.memory_section().map(|ms| ms.entries().len()).unwrap_or(0) } } @@ -582,13 +582,13 @@ impl Deserialize for Module { let mut magic = [0u8; 4]; reader.read(&mut magic)?; if magic != WASM_MAGIC_NUMBER { - return Err(Error::InvalidMagic) + return Err(Error::InvalidMagic); } let version: u32 = Uint32::deserialize(reader)?.into(); if version != 1 { - return Err(Error::UnsupportedVersion(version)) + return Err(Error::UnsupportedVersion(version)); } let mut last_section_order = 0; @@ -601,8 +601,9 @@ impl Deserialize for Module { if section.order() != 0 { match last_section_order { x if x > section.order() => return Err(Error::SectionsOutOfOrder), - x if x == section.order() => - return Err(Error::DuplicatedSections(last_section_order)), + x if x == section.order() => { + return Err(Error::DuplicatedSections(last_section_order)) + }, _ => {}, }; @@ -615,10 +616,10 @@ impl Deserialize for Module { let module = Module { magic: u32::from_le_bytes(magic), version, sections }; - if module.code_section().map(|cs| cs.bodies().len()).unwrap_or(0) != - module.function_section().map(|fs| fs.entries().len()).unwrap_or(0) + if module.code_section().map(|cs| cs.bodies().len()).unwrap_or(0) + != module.function_section().map(|fs| fs.entries().len()).unwrap_or(0) { - return Err(Error::InconsistentCode) + return Err(Error::InconsistentCode); } Ok(module) @@ -649,7 +650,7 @@ impl<'a> io::Read for PeekSection<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result<()> { let available = cmp::min(buf.len(), self.region.len() - self.cursor); if available < buf.len() { - return Err(io::Error::UnexpectedEof) + return Err(io::Error::UnexpectedEof); } let range = self.cursor..self.cursor + buf.len(); @@ -663,7 +664,7 @@ impl<'a> io::Read for PeekSection<'a> { /// Returns size of the module in the provided stream. pub fn peek_size(source: &[u8]) -> usize { if source.len() < 9 { - return 0 + return 0; } let mut cursor = 8; @@ -689,13 +690,13 @@ pub fn peek_size(source: &[u8]) -> usize { x if x > source.len() => break, x if x == source.len() => { cursor = next_cursor; - break + break; }, _ => {}, } cursor = next_cursor; } else { - break + break; } } @@ -774,7 +775,7 @@ mod integration_tests { deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); module.sections_mut().retain(|x| { if let Section::Code(_) = *x { - return true + return true; } matches!(*x, Section::Function(_)) }); diff --git a/src/elements/name_section.rs b/src/elements/name_section.rs index f1f3401..68b1a28 100644 --- a/src/elements/name_section.rs +++ b/src/elements/name_section.rs @@ -78,21 +78,21 @@ impl NameSection { match subsection_type { NAME_TYPE_MODULE => { if module_name.is_some() { - return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION)) + return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION)); } module_name = Some(ModuleNameSubsection::deserialize(rdr)?); }, NAME_TYPE_FUNCTION => { if function_names.is_some() { - return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION)) + return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION)); } function_names = Some(FunctionNameSubsection::deserialize(module, rdr)?); }, NAME_TYPE_LOCAL => { if local_names.is_some() { - return Err(Error::DuplicatedNameSubsections(NAME_TYPE_LOCAL)) + return Err(Error::DuplicatedNameSubsections(NAME_TYPE_LOCAL)); } local_names = Some(LocalNameSubsection::deserialize(module, rdr)?); }, diff --git a/src/elements/ops.rs b/src/elements/ops.rs index ebc7edc..a5266cf 100644 --- a/src/elements/ops.rs +++ b/src/elements/ops.rs @@ -50,7 +50,7 @@ impl Deserialize for Instructions { instructions.push(instruction); if block_count == 0 { - break + break; } } @@ -97,7 +97,7 @@ impl Deserialize for InitExpr { let is_terminal = instruction.is_terminal(); instructions.push(instruction); if is_terminal { - break + break; } } @@ -1089,7 +1089,7 @@ impl Deserialize for Instruction { let signature: u32 = VarUint32::deserialize(reader)?.into(); let table_ref: u8 = Uint8::deserialize(reader)?.into(); if table_ref != 0 { - return Err(Error::InvalidTableReference(table_ref)) + return Err(Error::InvalidTableReference(table_ref)); } CallIndirect(signature, table_ref) @@ -1221,14 +1221,14 @@ impl Deserialize for Instruction { CURRENTMEMORY => { let mem_ref: u8 = Uint8::deserialize(reader)?.into(); if mem_ref != 0 { - return Err(Error::InvalidMemoryReference(mem_ref)) + return Err(Error::InvalidMemoryReference(mem_ref)); } CurrentMemory(mem_ref) }, GROWMEMORY => { let mem_ref: u8 = Uint8::deserialize(reader)?.into(); if mem_ref != 0 { - return Err(Error::InvalidMemoryReference(mem_ref)) + return Err(Error::InvalidMemoryReference(mem_ref)); } GrowMemory(mem_ref) }, @@ -1657,34 +1657,34 @@ fn deserialize_bulk(reader: &mut R) -> Result { Ok(Instruction::Bulk(match val { MEMORY_INIT => { if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) + return Err(Error::UnknownOpcode(val)); } MemoryInit(VarUint32::deserialize(reader)?.into()) }, MEMORY_DROP => MemoryDrop(VarUint32::deserialize(reader)?.into()), MEMORY_FILL => { if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) + return Err(Error::UnknownOpcode(val)); } MemoryFill }, MEMORY_COPY => { if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) + return Err(Error::UnknownOpcode(val)); } MemoryCopy }, TABLE_INIT => { if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) + return Err(Error::UnknownOpcode(val)); } TableInit(VarUint32::deserialize(reader)?.into()) }, TABLE_DROP => TableDrop(VarUint32::deserialize(reader)?.into()), TABLE_COPY => { if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) + return Err(Error::UnknownOpcode(val)); } TableCopy }, @@ -2947,7 +2947,8 @@ fn ifelse() { .skip(1) .skip_while(|op| !matches!(**op, Instruction::Else)) .take_while(|op| !matches!(**op, Instruction::End)) - .count() - 1; // minus Instruction::Else itself + .count() + - 1; // minus Instruction::Else itself assert_eq!(before_else, after_else); } diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index 025e9b9..4b66c41 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -47,7 +47,7 @@ impl Deserialize for VarUint32 { let mut u8buf = [0u8; 1]; loop { if shift > 31 { - return Err(Error::InvalidVarUint32) + return Err(Error::InvalidVarUint32); } reader.read(&mut u8buf)?; @@ -56,9 +56,9 @@ impl Deserialize for VarUint32 { shift += 7; if (b >> 7) == 0 { if shift >= 32 && (b as u8).leading_zeros() < 4 { - return Err(Error::InvalidVarInt32) + return Err(Error::InvalidVarInt32); } - break + break; } } Ok(VarUint32(res)) @@ -79,7 +79,7 @@ impl Serialize for VarUint32 { } writer.write(&buf[..])?; if v == 0 { - break + break; } } @@ -107,7 +107,7 @@ impl Deserialize for VarUint64 { let mut u8buf = [0u8; 1]; loop { if shift > 63 { - return Err(Error::InvalidVarUint64) + return Err(Error::InvalidVarUint64); } reader.read(&mut u8buf)?; @@ -116,9 +116,9 @@ impl Deserialize for VarUint64 { shift += 7; if (b >> 7) == 0 { if shift >= 64 && (b as u8).leading_zeros() < 7 { - return Err(Error::InvalidVarInt64) + return Err(Error::InvalidVarInt64); } - break + break; } } Ok(VarUint64(res)) @@ -139,7 +139,7 @@ impl Serialize for VarUint64 { } writer.write(&buf[..])?; if v == 0 { - break + break; } } @@ -214,7 +214,7 @@ impl Deserialize for VarInt7 { // check if number is not continued! if u8buf[0] & 0b1000_0000 != 0 { - return Err(Error::InvalidVarInt7(u8buf[0])) + return Err(Error::InvalidVarInt7(u8buf[0])); } // expand sign @@ -302,7 +302,7 @@ impl Deserialize for VarInt32 { let mut u8buf = [0u8; 1]; loop { if shift > 31 { - return Err(Error::InvalidVarInt32) + return Err(Error::InvalidVarInt32); } reader.read(&mut u8buf)?; let b = u8buf[0]; @@ -315,12 +315,12 @@ impl Deserialize for VarInt32 { res |= (1i32 << shift).wrapping_neg(); } else if shift >= 32 && b & 0b0100_0000 == 0b0100_0000 { if (!(b | 0b1000_0000)).leading_zeros() < 5 { - return Err(Error::InvalidVarInt32) + return Err(Error::InvalidVarInt32); } } else if shift >= 32 && b & 0b0100_0000 == 0 && b.leading_zeros() < 5 { - return Err(Error::InvalidVarInt32) + return Err(Error::InvalidVarInt32); } - break + break; } } Ok(VarInt32(res)) @@ -337,8 +337,8 @@ impl Serialize for VarInt32 { while more { buf[0] = (v & 0b0111_1111) as u8; v >>= 7; - if (v == 0 && buf[0] & 0b0100_0000 == 0) || - (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) + if (v == 0 && buf[0] & 0b0100_0000 == 0) + || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { more = false } else { @@ -378,7 +378,7 @@ impl Deserialize for VarInt64 { loop { if shift > 63 { - return Err(Error::InvalidVarInt64) + return Err(Error::InvalidVarInt64); } reader.read(&mut u8buf)?; let b = u8buf[0]; @@ -391,12 +391,12 @@ impl Deserialize for VarInt64 { res |= (1i64 << shift).wrapping_neg(); } else if shift >= 64 && b & 0b0100_0000 == 0b0100_0000 { if (b | 0b1000_0000) as i8 != -1 { - return Err(Error::InvalidVarInt64) + return Err(Error::InvalidVarInt64); } } else if shift >= 64 && b != 0 { - return Err(Error::InvalidVarInt64) + return Err(Error::InvalidVarInt64); } - break + break; } } Ok(VarInt64(res)) @@ -413,8 +413,8 @@ impl Serialize for VarInt64 { while more { buf[0] = (v & 0b0111_1111) as u8; v >>= 7; - if (v == 0 && buf[0] & 0b0100_0000 == 0) || - (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) + if (v == 0 && buf[0] & 0b0100_0000 == 0) + || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { more = false } else { diff --git a/src/elements/segment.rs b/src/elements/segment.rs index 4eecd9d..173c78b 100644 --- a/src/elements/segment.rs +++ b/src/elements/segment.rs @@ -113,7 +113,7 @@ impl Deserialize for ElementSegment { } else if flags == FLAG_MEM_NONZERO { VarUint32::deserialize(reader)?.into() } else { - return Err(Error::InvalidSegmentFlags(flags)) + return Err(Error::InvalidSegmentFlags(flags)); }; let offset = if flags == FLAG_PASSIVE { None } else { Some(InitExpr::deserialize(reader)?) }; @@ -250,7 +250,7 @@ impl Deserialize for DataSegment { } else if flags == FLAG_MEM_NONZERO { VarUint32::deserialize(reader)?.into() } else { - return Err(Error::InvalidSegmentFlags(flags)) + return Err(Error::InvalidSegmentFlags(flags)); }; let offset = if flags == FLAG_PASSIVE { None } else { Some(InitExpr::deserialize(reader)?) }; diff --git a/src/elements/types.rs b/src/elements/types.rs index e7f680f..b6b6de7 100644 --- a/src/elements/types.rs +++ b/src/elements/types.rs @@ -201,7 +201,7 @@ impl Deserialize for FunctionType { let form: u8 = VarUint7::deserialize(reader)?.into(); if form != 0x60 { - return Err(Error::UnknownFunctionForm(form)) + return Err(Error::UnknownFunctionForm(form)); } let params: Vec = CountedList::deserialize(reader)?.into_inner(); @@ -211,7 +211,7 @@ impl Deserialize for FunctionType { if results.len() > 1 { return Err(Error::Other( "Enable the multi_value feature to deserialize more than one function result", - )) + )); } Ok(FunctionType { form, params, results }) diff --git a/src/io.rs b/src/io.rs index 653ef1c..4731b48 100644 --- a/src/io.rs +++ b/src/io.rs @@ -61,7 +61,7 @@ impl> Read for Cursor { let remainder = slice.len() - self.pos; let requested = buf.len(); if requested > remainder { - return Err(Error::UnexpectedEof) + return Err(Error::UnexpectedEof); } buf.copy_from_slice(&slice[self.pos..(self.pos + requested)]); self.pos += requested; From df34bf643dd9dd08ed0934e76f40120a261e6126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Papierski?= Date: Mon, 3 Feb 2025 16:11:00 +0000 Subject: [PATCH 2/9] Regression test --- src/elements/name_section.rs | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/elements/name_section.rs b/src/elements/name_section.rs index 68b1a28..a5259f6 100644 --- a/src/elements/name_section.rs +++ b/src/elements/name_section.rs @@ -294,6 +294,10 @@ pub type NameMap = IndexMap; #[cfg(test)] mod tests { + use std::io::Cursor; + + use crate::elements; + use super::*; // A helper function for the tests. Serialize a section, deserialize it, @@ -354,19 +358,23 @@ mod tests { } #[test] - fn deserialize_local_names() { - let module = super::super::deserialize_file("./res/cases/v1/names_with_imports.wasm") - .expect("Should be deserialized") - .parse_names() - .expect("Names to be parsed"); - - let name_section = module.names_section().expect("name_section should be present"); - let local_names = name_section.locals().expect("local_name_section should be present"); - - let locals = local_names.local_names().get(0).expect("entry #0 should be present"); - assert_eq!(locals.get(0).expect("entry #0 should be present"), "abc"); - - let locals = local_names.local_names().get(1).expect("entry #1 should be present"); - assert_eq!(locals.get(0).expect("entry #0 should be present"), "def"); + fn deserialize_invalid_name_section() { + let invalid = { + let mut invalid = Vec::new(); + VarUint7::from(u8::MAX).serialize(&mut invalid).unwrap(); + VarUint32::from(u32::MAX).serialize(&mut invalid).unwrap(); + invalid.extend_from_slice(&[0; 1024]); + invalid + }; + + let module = Module::new(Vec::new()); + + let mut cur = Cursor::new(invalid.as_slice()); + + let result = NameSection::deserialize(&module, &mut cur); + assert!( + matches!(&result, Err(elements::Error::HeapOther(msg)) if msg == "I/O Error: Io(Error { kind: UnexpectedEof, message: \"failed to fill whole buffer\" })"), + "{result:?}" + ); } } From b7ab20702c8fc4dde3d4e0aa8b1b984411e01d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Papierski?= Date: Mon, 3 Feb 2025 17:50:20 +0000 Subject: [PATCH 3/9] Fix the regression test --- .github/workflows/check.yml | 7 +++ Cargo.toml | 5 +- examples/bench-decoder.rs | 24 +++++---- examples/build.rs | 6 +++ examples/data.rs | 6 +++ examples/exports.rs | 5 ++ examples/info.rs | 6 +++ examples/inject.rs | 6 +++ examples/roundtrip.rs | 6 +++ examples/show.rs | 6 +++ rust-toolchain.toml | 2 + src/elements/index_map.rs | 5 +- src/elements/module.rs | 31 ++++++++++-- src/elements/name_section.rs | 30 ++++++----- src/elements/ops.rs | 93 ++++++++++++++++++----------------- src/elements/primitives.rs | 21 +++++--- src/elements/reloc_section.rs | 8 +-- src/elements/section.rs | 9 ++-- src/elements/segment.rs | 4 +- src/io.rs | 57 +++++++++++++++++++++ 20 files changed, 249 insertions(+), 88 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 8141ea4..c3690ff 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -95,3 +95,10 @@ jobs: toolchain: ${{ matrix.toolchain }} command: test args: --all-features --workspace + + - name: Cargo test with no-std + uses: actions-rs/cargo@v1 + with: + toolchain: ${{ matrix.toolchain }} + command: test + args: --no-default-features --workspace diff --git a/Cargo.toml b/Cargo.toml index 695e144..41490dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,13 +12,14 @@ keywords = ["wasm", "webassembly", "bytecode", "serde", "interpreter"] categories = ["wasm", "parser-implementations"] include = ["src/**/*", "LICENSE-*", "README.md"] edition = "2021" -rust-version = "1.56.1" +rust-version = "1.80.0" [workspace] members = ["testsuite"] [dev-dependencies] -time = "0.3" +hashbrown = "0.15.2" +cfg-if = "1.0.0" [features] default = ["std"] diff --git a/examples/bench-decoder.rs b/examples/bench-decoder.rs index 4f3cbbe..ebed120 100644 --- a/examples/bench-decoder.rs +++ b/examples/bench-decoder.rs @@ -1,33 +1,39 @@ extern crate casper_wasm; -extern crate time; - -use std::fs; -use time::Instant; +#[cfg(feature = "std")] fn rate(file_name: &'static str, iterations: u64) { + use std::fs; + + use std::time::{Duration, Instant}; + let file_size = fs::metadata(file_name) .unwrap_or_else(|_| panic!("{} to exist", file_name)) .len(); - let mut total_ms = 0; + let mut total = Duration::from_secs(0); for _ in 0..iterations { let start = Instant::now(); let _module = casper_wasm::deserialize_file(file_name); - let end = Instant::now(); + let end = start.elapsed(); - total_ms += (end - start).whole_milliseconds(); + total += end; } println!( "Rate for {}: {} MB/s", file_name, - (file_size as f64 * iterations as f64 / (1024*1024) as f64) / // total work megabytes - (total_ms as f64 / 1000f64) // total seconds + (file_size as f64 * iterations as f64 / (1024*1024) as f64) / // total work megabytes + (total.as_millis() as f64 / 1000f64) // total seconds ); } +#[cfg(feature = "std")] fn main() { rate("./res/cases/v1/clang.wasm", 10); rate("./res/cases/v1/hello.wasm", 100); rate("./res/cases/v1/with_names.wasm", 100); } +#[cfg(not(feature = "std"))] +fn main() { + panic!("Compilation requires --feature std") +} diff --git a/examples/build.rs b/examples/build.rs index 09ec68f..fe5facd 100644 --- a/examples/build.rs +++ b/examples/build.rs @@ -8,6 +8,7 @@ use std::env; use casper_wasm::{builder, elements}; +#[cfg(feature = "std")] fn main() { // Example binary accepts one parameter which is the output file // where generated wasm module will be written at the end of execution @@ -46,3 +47,8 @@ fn main() { // Module structure can be serialzed to produce a valid wasm file casper_wasm::serialize_to_file(&args[1], module).unwrap(); } + +#[cfg(not(feature = "std"))] +fn main() { + panic!("Compilation requires --feature std") +} diff --git a/examples/data.rs b/examples/data.rs index bb77605..a6d320d 100644 --- a/examples/data.rs +++ b/examples/data.rs @@ -5,6 +5,7 @@ extern crate casper_wasm; use std::env; +#[cfg(feature = "std")] fn main() { // Example executable takes one argument which must // refernce the existing file with a valid wasm module @@ -42,3 +43,8 @@ fn main() { println!(" size: {}", entry.value().len()); } } + +#[cfg(not(feature = "std"))] +fn main() { + panic!("Compilation requires --feature std") +} diff --git a/examples/exports.rs b/examples/exports.rs index 955187c..693bf28 100644 --- a/examples/exports.rs +++ b/examples/exports.rs @@ -41,6 +41,7 @@ fn type_by_index(module: &Module, index: usize) -> FunctionType { } } +#[cfg(feature = "std")] fn main() { // Example executable takes one argument which must // refernce the existing file with a valid wasm module @@ -83,3 +84,7 @@ fn main() { println!("{:}", export); } } +#[cfg(not(feature = "std"))] +fn main() { + panic!("Compilation requires --feature std") +} diff --git a/examples/info.rs b/examples/info.rs index ea3e458..e16446c 100644 --- a/examples/info.rs +++ b/examples/info.rs @@ -3,6 +3,7 @@ extern crate casper_wasm; use casper_wasm::elements::Section; use std::env; +#[cfg(feature = "std")] fn main() { let args = env::args().collect::>(); if args.len() != 2 { @@ -51,3 +52,8 @@ fn main() { } } } + +#[cfg(not(feature = "std"))] +fn main() { + panic!("Compilation requires --feature std") +} diff --git a/examples/inject.rs b/examples/inject.rs index a97a2e9..aabcc4f 100644 --- a/examples/inject.rs +++ b/examples/inject.rs @@ -21,6 +21,7 @@ pub fn inject_nop(instructions: &mut elements::Instructions) { } } +#[cfg(feature = "std")] fn main() { let args = env::args().collect::>(); if args.len() != 3 { @@ -46,3 +47,8 @@ fn main() { casper_wasm::serialize_to_file(&args[2], build.build()).unwrap(); } + +#[cfg(not(feature = "std"))] +fn main() { + panic!("Compilation requires --feature std") +} diff --git a/examples/roundtrip.rs b/examples/roundtrip.rs index 52f2efe..ade59ca 100644 --- a/examples/roundtrip.rs +++ b/examples/roundtrip.rs @@ -2,6 +2,7 @@ extern crate casper_wasm; use std::env; +#[cfg(feature = "std")] fn main() { let args = env::args().collect::>(); if args.len() != 3 { @@ -25,3 +26,8 @@ fn main() { casper_wasm::serialize_to_file(&args[2], module).expect("Failed to write module"); } + +#[cfg(not(feature = "std"))] +fn main() { + panic!("Compilation requires --feature std") +} diff --git a/examples/show.rs b/examples/show.rs index 36fac77..8016997 100644 --- a/examples/show.rs +++ b/examples/show.rs @@ -2,6 +2,7 @@ extern crate casper_wasm; use std::env; +#[cfg(feature = "std")] fn main() { let args = env::args().collect::>(); if args.len() != 3 { @@ -36,3 +37,8 @@ fn main() { println!("{}", instruction); } } + +#[cfg(not(feature = "std"))] +fn main() { + panic!("Compilation requires --features std") +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..fcb78ec --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.84.1" diff --git a/src/elements/index_map.rs b/src/elements/index_map.rs index 3812fe4..3107afb 100644 --- a/src/elements/index_map.rs +++ b/src/elements/index_map.rs @@ -178,7 +178,9 @@ where type Error = Error; fn serialize(self, wtr: &mut W) -> Result<(), Self::Error> { - VarUint32::from(self.len()).serialize(wtr)?; + VarUint32::try_from(self.len()) + .map_err(|_| Self::Error::InvalidVarInt32)? + .serialize(wtr)?; for (idx, value) in self.entries.into_iter() { VarUint32::from(idx).serialize(wtr)?; value.serialize(wtr)?; @@ -205,6 +207,7 @@ where #[cfg(test)] mod tests { use super::*; + use crate::alloc::string::{String, ToString}; use crate::io; #[test] diff --git a/src/elements/module.rs b/src/elements/module.rs index 2da1edf..e44c133 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -646,7 +646,7 @@ struct PeekSection<'a> { region: &'a [u8], } -impl<'a> io::Read for PeekSection<'a> { +impl io::Read for PeekSection<'_> { fn read(&mut self, buf: &mut [u8]) -> io::Result<()> { let available = cmp::min(buf.len(), self.region.len() - self.cursor); if available < buf.len() { @@ -705,14 +705,19 @@ pub fn peek_size(source: &[u8]) -> usize { #[cfg(test)] mod integration_tests { + #[cfg(feature = "std")] + use super::super::deserialize_file; use super::{ super::{ - deserialize_buffer, deserialize_file, serialize, CodeSection, ExportSection, - FunctionSection, Section, TypeSection, + deserialize_buffer, serialize, CodeSection, ExportSection, FunctionSection, Section, + TypeSection, }, Module, }; + use crate::alloc::string::ToString; + use crate::alloc::vec::Vec; + #[cfg(feature = "std")] #[test] fn hello() { let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized"); @@ -721,6 +726,7 @@ mod integration_tests { assert_eq!(module.sections().len(), 8); } + #[cfg(feature = "std")] #[test] fn serde() { let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); @@ -733,6 +739,7 @@ mod integration_tests { assert_eq!(module_old.sections().len(), module_new.sections().len()); } + #[cfg(feature = "std")] #[test] fn serde_type() { let mut module = @@ -751,6 +758,7 @@ mod integration_tests { ); } + #[cfg(feature = "std")] #[test] fn serde_import() { let mut module = @@ -769,6 +777,7 @@ mod integration_tests { ); } + #[cfg(feature = "std")] #[test] fn serde_code() { let mut module = @@ -792,6 +801,7 @@ mod integration_tests { ); } + #[cfg(feature = "std")] #[test] fn const_() { use super::super::Instruction::*; @@ -820,6 +830,7 @@ mod integration_tests { assert_eq!(I32Const(2147483647), func.code().elements()[17]); } + #[cfg(feature = "std")] #[test] fn store() { use super::super::Instruction::*; @@ -832,6 +843,7 @@ mod integration_tests { assert_eq!(I64Store(0, 32), func.code().elements()[2]); } + #[cfg(feature = "std")] #[test] fn peek() { use super::peek_size; @@ -844,6 +856,7 @@ mod integration_tests { assert_eq!(peek_size(&buf), buf.len() - 4); } + #[cfg(feature = "std")] #[test] fn peek_2() { use super::peek_size; @@ -857,6 +870,7 @@ mod integration_tests { assert_eq!(peek_size(&buf), buf.len() - 9); } + #[cfg(feature = "std")] #[test] fn peek_3() { use super::peek_size; @@ -877,6 +891,7 @@ mod integration_tests { assert_eq!(Module::default().magic, module2.magic); } + #[cfg(feature = "std")] #[test] fn names() { let module = deserialize_file("./res/cases/v1/with_names.wasm") @@ -905,6 +920,7 @@ mod integration_tests { assert!(found_section, "Name section should be present in dedicated example"); } + #[cfg(feature = "std")] #[test] fn names_with_global_section() { let module = deserialize_file("./res/cases/v1/global_section.wasm") @@ -934,12 +950,14 @@ mod integration_tests { } // This test fixture has FLAG_SHARED so it depends on atomics feature. + #[cfg(feature = "std")] #[test] fn shared_memory_flag() { let module = deserialize_file("./res/cases/v1/varuint1_1.wasm"); assert_eq!(module.is_ok(), cfg!(feature = "atomics")); } + #[cfg(feature = "std")] #[test] fn memory_space() { let module = @@ -947,6 +965,7 @@ mod integration_tests { assert_eq!(module.memory_space(), 2); } + #[cfg(feature = "std")] #[test] fn add_custom_section() { let mut module = @@ -966,6 +985,7 @@ mod integration_tests { assert!(module.custom_sections().next().is_none()); } + #[cfg(feature = "std")] #[test] fn mut_start() { let mut module = @@ -977,6 +997,7 @@ mod integration_tests { assert_eq!(None, module.start_section()); } + #[cfg(feature = "std")] #[test] fn add_start() { let mut module = @@ -989,6 +1010,7 @@ mod integration_tests { assert_eq!(sections, vec![1, 2, 3, 6, 7, 8, 9, 11, 12]); } + #[cfg(feature = "std")] #[test] fn add_start_custom() { let mut module = deserialize_file("./res/cases/v1/start_add_custom.wasm") @@ -1005,6 +1027,7 @@ mod integration_tests { assert_eq!(sections, vec![1, 2, 3, 6, 7, 8, 9, 11, 12, 0]); } + #[cfg(feature = "std")] #[test] fn names_section_present() { let mut module = @@ -1022,6 +1045,7 @@ mod integration_tests { assert!(module.has_names_section()); } + #[cfg(feature = "std")] #[test] fn names_section_not_present() { let mut module = @@ -1072,6 +1096,7 @@ mod integration_tests { assert!(deserialize_buffer::(&serialized).is_ok()); } + #[cfg(feature = "std")] #[test] fn serialization_roundtrip() { let module = deserialize_file("./res/cases/v1/test.wasm").expect("failed to deserialize"); diff --git a/src/elements/name_section.rs b/src/elements/name_section.rs index a5259f6..f940370 100644 --- a/src/elements/name_section.rs +++ b/src/elements/name_section.rs @@ -65,7 +65,10 @@ impl NameSection { impl NameSection { /// Deserialize a name section. - pub fn deserialize(module: &Module, rdr: &mut R) -> Result { + pub fn deserialize( + module: &Module, + rdr: &mut R, + ) -> Result { let mut module_name: Option = None; let mut function_names: Option = None; let mut local_names: Option = None; @@ -98,10 +101,12 @@ impl NameSection { }, _ => { - // Consume the entire subsection size and drop it. This allows other sections to still be - // consumed if there are any. - let mut buf = vec![0; size]; - rdr.read(&mut buf)?; + let size: i64 = size.try_into().map_err(|_| Error::UnexpectedEof)?; + rdr.seek_relative(size)?; + // Behavior of seeking past the length is implementation defined + if rdr.stream_position()? > rdr.stream_len()? { + return Err(Error::UnexpectedEof); + } }, }; } @@ -120,7 +125,9 @@ impl Serialize for NameSection { name_payload: &[u8], ) -> Result<(), Error> { VarUint7::from(name_type).serialize(wtr)?; - VarUint32::from(name_payload.len()).serialize(wtr)?; + VarUint32::try_from(name_payload.len()) + .map_err(|_| Error::InvalidVarInt32)? + .serialize(wtr)?; wtr.write(name_payload).map_err(Into::into) } @@ -294,8 +301,7 @@ pub type NameMap = IndexMap; #[cfg(test)] mod tests { - use std::io::Cursor; - + use crate::alloc::{string::ToString, vec::Vec}; use crate::elements; use super::*; @@ -369,12 +375,10 @@ mod tests { let module = Module::new(Vec::new()); - let mut cur = Cursor::new(invalid.as_slice()); + let mut cur = crate::io::Cursor::new(invalid.as_slice()); let result = NameSection::deserialize(&module, &mut cur); - assert!( - matches!(&result, Err(elements::Error::HeapOther(msg)) if msg == "I/O Error: Io(Error { kind: UnexpectedEof, message: \"failed to fill whole buffer\" })"), - "{result:?}" - ); + + assert!(matches!(&result, Err(elements::Error::UnexpectedEof)), "{result:?}"); } } diff --git a/src/elements/ops.rs b/src/elements/ops.rs index a5266cf..52bc767 100644 --- a/src/elements/ops.rs +++ b/src/elements/ops.rs @@ -2925,56 +2925,59 @@ impl Serialize for InitExpr { } } -#[test] -fn ifelse() { - // see if-else.wast/if-else.wasm - let instruction_list = super::deserialize_buffer::(&[ - 0x04, 0x7F, 0x41, 0x05, 0x05, 0x41, 0x07, 0x0B, 0x0B, - ]) - .expect("valid hex of if instruction"); - let instructions = instruction_list.elements(); - match instructions[0] { - Instruction::If(_) => (), - _ => panic!("Should be deserialized as if instruction"), +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn ifelse() { + // see if-else.wast/if-else.wasm + let instruction_list = crate::elements::deserialize_buffer::(&[ + 0x04, 0x7F, 0x41, 0x05, 0x05, 0x41, 0x07, 0x0B, 0x0B, + ]) + .expect("valid hex of if instruction"); + let instructions = instruction_list.elements(); + match instructions[0] { + Instruction::If(_) => (), + _ => panic!("Should be deserialized as if instruction"), + } + let before_else = instructions + .iter() + .skip(1) + .take_while(|op| !matches!(**op, Instruction::Else)) + .count(); + let after_else = instructions + .iter() + .skip(1) + .skip_while(|op| !matches!(**op, Instruction::Else)) + .take_while(|op| !matches!(**op, Instruction::End)) + .count() - 1; // minus Instruction::Else itself + assert_eq!(before_else, after_else); } - let before_else = instructions - .iter() - .skip(1) - .take_while(|op| !matches!(**op, Instruction::Else)) - .count(); - let after_else = instructions - .iter() - .skip(1) - .skip_while(|op| !matches!(**op, Instruction::Else)) - .take_while(|op| !matches!(**op, Instruction::End)) - .count() - - 1; // minus Instruction::Else itself - assert_eq!(before_else, after_else); -} -#[test] -fn display() { - let instruction = Instruction::GetLocal(0); - assert_eq!("get_local 0", format!("{}", instruction)); + #[test] + fn display() { + let instruction = Instruction::GetLocal(0); + assert_eq!("get_local 0", format!("{}", instruction)); - let instruction = Instruction::F64Store(0, 24); - assert_eq!("f64.store offset=24", format!("{}", instruction)); + let instruction = Instruction::F64Store(0, 24); + assert_eq!("f64.store offset=24", format!("{}", instruction)); - let instruction = Instruction::I64Store(0, 0); - assert_eq!("i64.store", format!("{}", instruction)); -} + let instruction = Instruction::I64Store(0, 0); + assert_eq!("i64.store", format!("{}", instruction)); + } -#[test] -fn size_off() { - assert!(::std::mem::size_of::() <= 24); -} + #[test] + fn size_off() { + assert!(::core::mem::size_of::() <= 24); + } -#[test] -fn instructions_hashset() { - use self::Instruction::{Block, Call, Drop}; - use super::types::{BlockType::Value, ValueType}; + #[test] + fn instructions_hashset() { + use self::Instruction::{Block, Call, Drop}; + use crate::elements::types::{BlockType::Value, ValueType}; - let set: std::collections::HashSet = - vec![Call(1), Block(Value(ValueType::I32)), Drop].into_iter().collect(); - assert!(set.contains(&Drop)); + let set: hashbrown::HashSet = + vec![Call(1), Block(Value(ValueType::I32)), Drop].into_iter().collect(); + assert!(set.contains(&Drop)); + } } diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index 4b66c41..98545f6 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -31,10 +31,13 @@ impl From for VarUint32 { } } -impl From for VarUint32 { - fn from(i: usize) -> VarUint32 { - assert!(i <= u32::max_value() as usize); - VarUint32(i as u32) +pub struct TryFromUsizeForVarUint32(()); + +impl TryFrom for VarUint32 { + type Error = TryFromUsizeForVarUint32; + fn try_from(i: usize) -> Result { + let value: u32 = i.try_into().map_err(|_| TryFromUsizeForVarUint32(()))?; + Ok(VarUint32(value)) } } @@ -557,7 +560,9 @@ impl Serialize for String { type Error = Error; fn serialize(self, writer: &mut W) -> Result<(), Error> { - VarUint32::from(self.len()).serialize(writer)?; + VarUint32::try_from(self.len()) + .map_err(|_| Self::Error::InvalidVarInt32)? + .serialize(writer)?; writer.write(&self.into_bytes()[..])?; Ok(()) } @@ -610,7 +615,8 @@ impl<'a, W: 'a + io::Write> CountedWriter<'a, W> { pub fn done(self) -> io::Result<()> { let writer = self.writer; let data = self.data; - VarUint32::from(data.len()) + VarUint32::try_from(data.len()) + .map_err(|_| io::Error::InvalidInput)? .serialize(writer) .map_err(|_| io::Error::InvalidData)?; writer.write(&data[..])?; @@ -641,7 +647,7 @@ impl, T: IntoIterator> Serialize fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { let len_us = self.0; let data = self.1; - let len: VarUint32 = len_us.into(); + let len: VarUint32 = len_us.try_into().map_err(|_| Error::InvalidVarUint32)?; len.serialize(writer)?; for data_element in data { data_element.serialize(writer)? @@ -658,6 +664,7 @@ mod tests { super::{deserialize_buffer, Serialize}, CountedList, VarInt32, VarInt64, VarInt7, VarUint32, VarUint64, }; + use crate::alloc::vec::Vec; use crate::elements::Error; fn varuint32_ser_test(val: u32, expected: Vec) { diff --git a/src/elements/reloc_section.rs b/src/elements/reloc_section.rs index a2284e5..4333a49 100644 --- a/src/elements/reloc_section.rs +++ b/src/elements/reloc_section.rs @@ -311,11 +311,11 @@ impl Serialize for RelocationEntry { #[cfg(test)] mod tests { - use super::{ - super::{deserialize_file, Section}, - RelocationEntry, - }; + #[cfg(feature = "std")] + use super::super::deserialize_file; + use super::{super::Section, RelocationEntry}; + #[cfg(feature = "std")] #[test] fn reloc_section() { let module = deserialize_file("./res/cases/v1/relocatable.wasm") diff --git a/src/elements/section.rs b/src/elements/section.rs index 9c2badd..30875b9 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -289,7 +289,7 @@ impl Deserialize for CustomSection { let buf = buffered_read!(ENTRIES_BUFFER_LENGTH, section_length, reader); let mut cursor = io::Cursor::new(&buf[..]); let name = String::deserialize(&mut cursor)?; - let payload = buf[cursor.position() as usize..].to_vec(); + let payload = buf[cursor.position()..].to_vec(); Ok(CustomSection { name, payload }) } } @@ -759,14 +759,17 @@ impl Serialize for DataSection { #[cfg(test)] mod tests { + #[cfg(feature = "std")] + use super::super::deserialize_file; use super::{ super::{ - deserialize_buffer, deserialize_file, serialize, BlockType, DataSegment, - ElementSegment, FuncBody, InitExpr, Instructions, Local, ValueType, + deserialize_buffer, serialize, BlockType, DataSegment, ElementSegment, FuncBody, + InitExpr, Instructions, Local, ValueType, }, CodeSection, DataSection, ElementSection, Section, Type, TypeSection, }; + #[cfg(feature = "std")] #[test] fn import_section() { let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); diff --git a/src/elements/segment.rs b/src/elements/segment.rs index 173c78b..178e1eb 100644 --- a/src/elements/segment.rs +++ b/src/elements/segment.rs @@ -284,7 +284,9 @@ impl Serialize for DataSegment { } let value = self.value; - VarUint32::from(value.len()).serialize(writer)?; + VarUint32::try_from(value.len()) + .map_err(|_| Error::InvalidVarUint32)? + .serialize(writer)?; writer.write(&value[..])?; Ok(()) } diff --git a/src/io.rs b/src/io.rs index 4731b48..79f1627 100644 --- a/src/io.rs +++ b/src/io.rs @@ -18,6 +18,9 @@ pub enum Error { /// Invalid data is encountered. InvalidData, + /// Invalid input. + InvalidInput, + #[cfg(feature = "std")] Io(std::io::Error), } @@ -39,6 +42,15 @@ pub trait Read { fn read(&mut self, buf: &mut [u8]) -> Result<()>; } +pub trait Seek { + /// Seeks relative to the current position in the stream. + fn seek_relative(&mut self, offset: i64) -> Result<()>; + /// Returns the current seek position from the start of the stream. + fn stream_position(&mut self) -> Result; + /// Returns the current length of this stream (in bytes). + fn stream_len(&mut self) -> Result; +} + /// Reader that saves the last position. pub struct Cursor { inner: T, @@ -69,6 +81,22 @@ impl> Read for Cursor { } } +impl> Seek for Cursor { + fn seek_relative(&mut self, offset: i64) -> Result<()> { + let offset: usize = offset.try_into().map_err(|_| Error::InvalidInput)?; + self.pos = self.pos.checked_add(offset).ok_or(Error::InvalidInput)?; + Ok(()) + } + + fn stream_position(&mut self) -> Result { + self.pos.try_into().map_err(|_| Error::InvalidInput) + } + + fn stream_len(&mut self) -> Result { + self.inner.as_ref().len().try_into().map_err(|_| Error::InvalidInput) + } +} + #[cfg(not(feature = "std"))] impl Write for alloc::vec::Vec { fn write(&mut self, buf: &[u8]) -> Result<()> { @@ -84,6 +112,24 @@ impl Read for T { } } +#[cfg(feature = "std")] +impl Seek for T { + fn seek_relative(&mut self, pos: i64) -> Result<()> { + self.seek_relative(pos).map_err(Error::Io) + } + + fn stream_position(&mut self) -> Result { + self.stream_position().map_err(Error::Io) + } + + fn stream_len(&mut self) -> Result { + let current_position = self.stream_position().map_err(Error::Io)?; + let end_pos = self.seek(std::io::SeekFrom::End(0)).map_err(Error::Io)?; + self.seek(std::io::SeekFrom::Start(current_position)).map_err(Error::Io)?; + Ok(end_pos) + } +} + #[cfg(feature = "std")] impl Write for T { fn write(&mut self, buf: &[u8]) -> Result<()> { @@ -115,4 +161,15 @@ mod tests { let mut buf = [0, 1, 2]; assert!(cursor.read(&mut buf[..]).is_err()); } + + #[test] + fn overflowing_seek() { + let mut cursor = Cursor::new(vec![0u8, 1, 2]); + + // Seek past end works, it is impl dependent similar to the std crate. + cursor.seek_relative(i64::MAX).unwrap(); + cursor.seek_relative(i64::MAX).unwrap(); + // This should overflow usize + assert!(matches!(cursor.seek_relative(2).unwrap_err(), Error::InvalidInput)); + } } From e52949a292dac533affec0b02f917c5ed590e930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Papierski?= Date: Tue, 4 Feb 2025 12:43:51 +0000 Subject: [PATCH 4/9] Update comment --- src/elements/name_section.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/elements/name_section.rs b/src/elements/name_section.rs index f940370..3672b8b 100644 --- a/src/elements/name_section.rs +++ b/src/elements/name_section.rs @@ -101,9 +101,9 @@ impl NameSection { }, _ => { - let size: i64 = size.try_into().map_err(|_| Error::UnexpectedEof)?; - rdr.seek_relative(size)?; - // Behavior of seeking past the length is implementation defined + let offset: i64 = size.try_into().map_err(|_| Error::UnexpectedEof)?; + rdr.seek_relative(offset)?; + // Behavior of seeking past the length is implementation defined, so we need a way to force an EOF error. if rdr.stream_position()? > rdr.stream_len()? { return Err(Error::UnexpectedEof); } From 6e844ebd6312264bcc0f52e13be48b33bf0b8001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Papierski?= Date: Tue, 4 Feb 2025 18:24:36 +0100 Subject: [PATCH 5/9] Remove unneeded crate --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 41490dc..4a1cdbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ members = ["testsuite"] [dev-dependencies] hashbrown = "0.15.2" -cfg-if = "1.0.0" [features] default = ["std"] From cb4dcc9c20f95f40815e1aec2324b5b5aafcb1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Papierski?= Date: Tue, 4 Feb 2025 18:29:08 +0100 Subject: [PATCH 6/9] Update branch name --- .github/workflows/check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index c3690ff..760a37b 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -2,9 +2,9 @@ name: Check on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] env: CARGO_TERM_COLOR: always From e55e758f71c7da29793041ea4ccc62d77c88dfda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Papierski?= Date: Tue, 4 Feb 2025 18:32:43 +0100 Subject: [PATCH 7/9] Fix formatting --- src/elements/index_map.rs | 6 ++++-- src/elements/mod.rs | 5 ++--- src/elements/module.rs | 36 +++++++++++++++++------------------- src/elements/name_section.rs | 6 ++++-- src/elements/primitives.rs | 11 +++++------ 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/elements/index_map.rs b/src/elements/index_map.rs index 3107afb..796bcea 100644 --- a/src/elements/index_map.rs +++ b/src/elements/index_map.rs @@ -207,8 +207,10 @@ where #[cfg(test)] mod tests { use super::*; - use crate::alloc::string::{String, ToString}; - use crate::io; + use crate::{ + alloc::string::{String, ToString}, + io, + }; #[test] fn default_is_empty_no_matter_how_we_look_at_it() { diff --git a/src/elements/mod.rs b/src/elements/mod.rs index c076d87..750a892 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -256,9 +256,8 @@ impl ::std::error::Error for Error { Error::InvalidTableReference(_) => "Invalid table reference", Error::InvalidLimitsFlags(_) => "Invalid limits flags", Error::UnknownFunctionForm(_) => "Unknown function form", - Error::InconsistentCode => { - "Number of function body entries and signatures does not match" - }, + Error::InconsistentCode => + "Number of function body entries and signatures does not match", Error::InvalidSegmentFlags(_) => "Invalid segment flags", Error::TooManyLocals => "Too many locals", Error::DuplicatedNameSubsections(_) => "Duplicated name subsections", diff --git a/src/elements/module.rs b/src/elements/module.rs index e44c133..cb07eb0 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -537,10 +537,10 @@ impl Module { .filter(|import| { matches!( (count_type, *import.external()), - (ImportCountType::Function, External::Function(_)) - | (ImportCountType::Global, External::Global(_)) - | (ImportCountType::Table, External::Table(_)) - | (ImportCountType::Memory, External::Memory(_)) + (ImportCountType::Function, External::Function(_)) | + (ImportCountType::Global, External::Global(_)) | + (ImportCountType::Table, External::Table(_)) | + (ImportCountType::Memory, External::Memory(_)) ) }) .count() @@ -550,26 +550,26 @@ impl Module { /// Query functions space. pub fn functions_space(&self) -> usize { - self.import_count(ImportCountType::Function) - + self.function_section().map(|fs| fs.entries().len()).unwrap_or(0) + self.import_count(ImportCountType::Function) + + self.function_section().map(|fs| fs.entries().len()).unwrap_or(0) } /// Query globals space. pub fn globals_space(&self) -> usize { - self.import_count(ImportCountType::Global) - + self.global_section().map(|gs| gs.entries().len()).unwrap_or(0) + self.import_count(ImportCountType::Global) + + self.global_section().map(|gs| gs.entries().len()).unwrap_or(0) } /// Query table space. pub fn table_space(&self) -> usize { - self.import_count(ImportCountType::Table) - + self.table_section().map(|ts| ts.entries().len()).unwrap_or(0) + self.import_count(ImportCountType::Table) + + self.table_section().map(|ts| ts.entries().len()).unwrap_or(0) } /// Query memory space. pub fn memory_space(&self) -> usize { - self.import_count(ImportCountType::Memory) - + self.memory_section().map(|ms| ms.entries().len()).unwrap_or(0) + self.import_count(ImportCountType::Memory) + + self.memory_section().map(|ms| ms.entries().len()).unwrap_or(0) } } @@ -601,9 +601,8 @@ impl Deserialize for Module { if section.order() != 0 { match last_section_order { x if x > section.order() => return Err(Error::SectionsOutOfOrder), - x if x == section.order() => { - return Err(Error::DuplicatedSections(last_section_order)) - }, + x if x == section.order() => + return Err(Error::DuplicatedSections(last_section_order)), _ => {}, }; @@ -616,8 +615,8 @@ impl Deserialize for Module { let module = Module { magic: u32::from_le_bytes(magic), version, sections }; - if module.code_section().map(|cs| cs.bodies().len()).unwrap_or(0) - != module.function_section().map(|fs| fs.entries().len()).unwrap_or(0) + if module.code_section().map(|cs| cs.bodies().len()).unwrap_or(0) != + module.function_section().map(|fs| fs.entries().len()).unwrap_or(0) { return Err(Error::InconsistentCode); } @@ -714,8 +713,7 @@ mod integration_tests { }, Module, }; - use crate::alloc::string::ToString; - use crate::alloc::vec::Vec; + use crate::alloc::{string::ToString, vec::Vec}; #[cfg(feature = "std")] #[test] diff --git a/src/elements/name_section.rs b/src/elements/name_section.rs index 3672b8b..f0d333d 100644 --- a/src/elements/name_section.rs +++ b/src/elements/name_section.rs @@ -301,8 +301,10 @@ pub type NameMap = IndexMap; #[cfg(test)] mod tests { - use crate::alloc::{string::ToString, vec::Vec}; - use crate::elements; + use crate::{ + alloc::{string::ToString, vec::Vec}, + elements, + }; use super::*; diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index 98545f6..0b9afe6 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -340,8 +340,8 @@ impl Serialize for VarInt32 { while more { buf[0] = (v & 0b0111_1111) as u8; v >>= 7; - if (v == 0 && buf[0] & 0b0100_0000 == 0) - || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) + if (v == 0 && buf[0] & 0b0100_0000 == 0) || + (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { more = false } else { @@ -416,8 +416,8 @@ impl Serialize for VarInt64 { while more { buf[0] = (v & 0b0111_1111) as u8; v >>= 7; - if (v == 0 && buf[0] & 0b0100_0000 == 0) - || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) + if (v == 0 && buf[0] & 0b0100_0000 == 0) || + (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { more = false } else { @@ -664,8 +664,7 @@ mod tests { super::{deserialize_buffer, Serialize}, CountedList, VarInt32, VarInt64, VarInt7, VarUint32, VarUint64, }; - use crate::alloc::vec::Vec; - use crate::elements::Error; + use crate::{alloc::vec::Vec, elements::Error}; fn varuint32_ser_test(val: u32, expected: Vec) { let mut buf = Vec::new(); From 06ad5ee90249765b9616039bed5b773e431bb3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Papierski?= Date: Wed, 5 Feb 2025 18:25:55 +0100 Subject: [PATCH 8/9] Fix typos --- examples/data.rs | 2 +- examples/exports.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/data.rs b/examples/data.rs index a6d320d..e689cae 100644 --- a/examples/data.rs +++ b/examples/data.rs @@ -8,7 +8,7 @@ use std::env; #[cfg(feature = "std")] fn main() { // Example executable takes one argument which must - // refernce the existing file with a valid wasm module + // reference the existing file with a valid wasm module let args = env::args().collect::>(); if args.len() != 2 { println!("Usage: {} somefile.wasm", args[0]); diff --git a/examples/exports.rs b/examples/exports.rs index 693bf28..e7d1281 100644 --- a/examples/exports.rs +++ b/examples/exports.rs @@ -44,7 +44,7 @@ fn type_by_index(module: &Module, index: usize) -> FunctionType { #[cfg(feature = "std")] fn main() { // Example executable takes one argument which must - // refernce the existing file with a valid wasm module + // reference the existing file with a valid wasm module let args: Vec<_> = args().collect(); if args.len() < 2 { println!("Prints export function names with and their types"); From 69d644cdeee7fc07ef0239fe048c6fe89f8a3e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Papierski?= Date: Wed, 5 Feb 2025 18:38:07 +0100 Subject: [PATCH 9/9] Bump version --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4a1cdbe..0b2371d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "casper-wasm" -version = "0.46.0" -authors = ["Nikolay Volf ", "Svyatoslav Nikolsky ", "Sergey Shulepov "] +version = "0.46.1" +authors = ["Nikolay Volf ", "Svyatoslav Nikolsky ", "Sergey Shulepov ", "Michał Papierski "] license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/casper-network/casper-wasm"