improve name section parsing

This commit is contained in:
vms 2019-03-23 20:00:57 +03:00
parent ca99b786ed
commit 6b78411a21
3 changed files with 144 additions and 80 deletions

View File

@ -53,8 +53,8 @@ pub use self::func::{Func, FuncBody, Local};
pub use self::segment::{ElementSegment, DataSegment}; pub use self::segment::{ElementSegment, DataSegment};
pub use self::index_map::IndexMap; pub use self::index_map::IndexMap;
pub use self::name_section::{ pub use self::name_section::{
NameMap, NameSection, ModuleNameSection, FunctionNameSection, NameMap, NameSection, ModuleNameSubsection, FunctionNameSubsection,
LocalNameSection, LocalNameSubsection,
}; };
pub use self::reloc_section::{ pub use self::reloc_section::{
RelocSection, RelocationEntry, RelocSection, RelocationEntry,
@ -145,6 +145,10 @@ pub enum Error {
InvalidSegmentFlags(u32), InvalidSegmentFlags(u32),
/// Sum of counts of locals is greater than 2^32. /// Sum of counts of locals is greater than 2^32.
TooManyLocals, TooManyLocals,
/// Duplicated name subsections.
DuplicatedNameSubsections(u8),
/// Unknown name subsection type.
UnknownNameSubsectionType(u8),
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@ -174,7 +178,7 @@ impl fmt::Display for Error {
Error::InconsistentMetadata => write!(f, "Inconsistent metadata"), Error::InconsistentMetadata => write!(f, "Inconsistent metadata"),
Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id),
Error::SectionsOutOfOrder => write!(f, "Sections out of order"), Error::SectionsOutOfOrder => write!(f, "Sections out of order"),
Error::DuplicatedSections(ref id) => write!(f, "Dupliated sections ({})", id), Error::DuplicatedSections(ref id) => write!(f, "Duplicated sections ({})", id),
Error::InvalidMemoryReference(ref mem_ref) => write!(f, "Invalid memory reference ({})", mem_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::InvalidTableReference(ref table_ref) => write!(f, "Invalid table reference ({})", table_ref),
Error::InvalidLimitsFlags(ref flags) => write!(f, "Invalid limits flags ({})", flags), Error::InvalidLimitsFlags(ref flags) => write!(f, "Invalid limits flags ({})", flags),
@ -182,6 +186,8 @@ impl fmt::Display for Error {
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::InvalidSegmentFlags(n) => write!(f, "Invalid segment flags: {}", n),
Error::TooManyLocals => write!(f, "Too many locals"), Error::TooManyLocals => write!(f, "Too many locals"),
Error::DuplicatedNameSubsections(n) => write!(f, "Duplicated name sections: {}", n),
Error::UnknownNameSubsectionType(n) => write!(f, "Unknown subsection type: {}", n),
} }
} }
} }
@ -220,6 +226,8 @@ impl ::std::error::Error for Error {
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::InvalidSegmentFlags(_) => "Invalid segment flags",
Error::TooManyLocals => "Too many locals", Error::TooManyLocals => "Too many locals",
Error::DuplicatedNameSubsections(_) => "Duplicated name sections",
Error::UnknownNameSubsectionType(_) => "Unknown name subsections type",
} }
} }
} }

View File

@ -346,7 +346,7 @@ impl Module {
None None
} }
/// Try to parse name section in place/ /// Try to parse name section in place.
/// ///
/// Corresponding custom section with proper header will convert to name sections /// Corresponding custom section with proper header will convert to name sections
/// If some of them will fail to be decoded, Err variant is returned with the list of /// If some of them will fail to be decoded, Err variant is returned with the list of
@ -364,12 +364,17 @@ impl Module {
Ok(ns) => ns, Ok(ns) => ns,
Err(e) => { parse_errors.push((i, e)); continue; } Err(e) => { parse_errors.push((i, e)); continue; }
}; };
if rdr.position() != custom.payload().len() {
parse_errors.push((i, io::Error::InvalidData.into()));
break;
}
Some(name_section) Some(name_section)
} else { } else {
None None
} }
} else { None } } else { None }
} { } {
// TODO: according to the spec a Wasm binary can contain only one name section
*self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section); *self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section);
} }
} }

View File

@ -10,23 +10,47 @@ const NAME_TYPE_LOCAL: u8 = 2;
/// Debug name information. /// Debug name information.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum NameSection { pub struct NameSection {
/// Module name section. /// Module name subsection.
Module(ModuleNameSection), module_name_subsection: Option<ModuleNameSubsection>,
/// Function name section. /// Function name subsection.
Function(FunctionNameSection), function_name_subsection: Option<FunctionNameSubsection>,
/// Local name section. /// Local name subsection.
Local(LocalNameSection), local_name_subsection: Option<LocalNameSubsection>,
}
/// Name section is unparsed. impl NameSection {
Unparsed { /// Module name subsection of this section.
/// The numeric identifier for this name section type. pub fn module_name_subsection(&self) -> Option<&ModuleNameSubsection> {
name_type: u8, self.module_name_subsection.as_ref()
/// The contents of this name section, unparsed. }
name_payload: Vec<u8>,
}, /// Module name subsection of this section (mutable).
pub fn module_name_subsection_mut(&mut self) -> &mut Option<ModuleNameSubsection> {
&mut self.module_name_subsection
}
/// Functions name subsection of this section.
pub fn function_name_subsection(&self) -> Option<&FunctionNameSubsection> {
self.function_name_subsection.as_ref()
}
/// Functions name subsection of this section (mutable).
pub fn function_name_subsection_mut(&mut self) -> &mut Option<FunctionNameSubsection> {
&mut self.function_name_subsection
}
/// Local name subsection of this section.
pub fn local_name_subsection(&self) -> Option<&LocalNameSubsection> {
self.local_name_subsection.as_ref()
}
/// Local name subsection of this section (mutable).
pub fn local_name_subsection_mut(&mut self) -> &mut Option<LocalNameSubsection> {
&mut self.local_name_subsection
}
} }
impl NameSection { impl NameSection {
@ -34,23 +58,50 @@ impl NameSection {
pub fn deserialize<R: io::Read>( pub fn deserialize<R: io::Read>(
module: &Module, module: &Module,
rdr: &mut R, rdr: &mut R,
) -> Result<NameSection, Error> { ) -> Result<Self, Error> {
let name_type: u8 = VarUint7::deserialize(rdr)?.into(); let mut module_name_subsection: Option<ModuleNameSubsection> = None;
let name_payload_len: u32 = VarUint32::deserialize(rdr)?.into(); let mut function_name_subsection: Option<FunctionNameSubsection> = None;
let name_section = match name_type { let mut local_name_subsection: Option<LocalNameSubsection> = None;
NAME_TYPE_MODULE => NameSection::Module(ModuleNameSection::deserialize(rdr)?),
NAME_TYPE_FUNCTION => NameSection::Function(FunctionNameSection::deserialize(module, rdr)?), loop {
NAME_TYPE_LOCAL => NameSection::Local(LocalNameSection::deserialize(module, rdr)?), let subsection_type: u8 = match VarUint7::deserialize(rdr) {
_ => { Ok(raw_subsection_type) => raw_subsection_type.into(),
let mut name_payload = vec![0u8; name_payload_len as usize]; // there is no data to read -> there is no other subsections
rdr.read(&mut name_payload)?; Err(Error::UnexpectedEof) => break,
NameSection::Unparsed { Err(error) => return Err(error),
name_type, };
name_payload,
} match subsection_type {
} NAME_TYPE_MODULE => {
}; if let Some(_) = module_name_subsection {
Ok(name_section) return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION));
}
module_name_subsection = Some(ModuleNameSubsection::deserialize(rdr)?);
},
NAME_TYPE_FUNCTION => {
if let Some(_) = function_name_subsection {
return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION));
}
function_name_subsection = Some(FunctionNameSubsection::deserialize(module, rdr)?);
},
NAME_TYPE_LOCAL => {
if let Some(_) = local_name_subsection {
return Err(Error::DuplicatedNameSubsections(NAME_TYPE_LOCAL));
}
local_name_subsection = Some(LocalNameSubsection::deserialize(module, rdr)?);
},
_ => return Err(Error::UnknownNameSubsectionType(subsection_type))
};
}
Ok(NameSection {
module_name_subsection,
function_name_subsection,
local_name_subsection,
})
} }
} }
@ -58,44 +109,44 @@ impl Serialize for NameSection {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> { fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
let (name_type, name_payload) = match self { fn serialize_subsection<W: io::Write>(wtr: &mut W, name_type: u8, name_payload: &Vec<u8>) -> Result<(), Error> {
NameSection::Module(mod_name) => { VarUint7::from(name_type).serialize(wtr)?;
let mut buffer = vec![]; VarUint32::from(name_payload.len()).serialize(wtr)?;
mod_name.serialize(&mut buffer)?; wtr.write(name_payload).map_err(Into::into)
(NAME_TYPE_MODULE, buffer) }
}
NameSection::Function(fn_names) => { if let Some(module_name_subsection) = self.module_name_subsection {
let mut buffer = vec![]; let mut buffer = vec![];
fn_names.serialize(&mut buffer)?; module_name_subsection.serialize(&mut buffer)?;
(NAME_TYPE_FUNCTION, buffer) serialize_subsection(wtr, NAME_TYPE_MODULE, &buffer)?;
} }
NameSection::Local(local_names) => {
let mut buffer = vec![]; if let Some(function_name_subsection) = self.function_name_subsection {
local_names.serialize(&mut buffer)?; let mut buffer = vec![];
(NAME_TYPE_LOCAL, buffer) function_name_subsection.serialize(&mut buffer)?;
} serialize_subsection(wtr, NAME_TYPE_FUNCTION, &buffer)?;
NameSection::Unparsed { }
name_type,
name_payload, if let Some(local_name_subsection) = self.local_name_subsection {
} => (name_type, name_payload), let mut buffer = vec![];
}; local_name_subsection.serialize(&mut buffer)?;
VarUint7::from(name_type).serialize(wtr)?; serialize_subsection(wtr, NAME_TYPE_LOCAL, &buffer)?;
VarUint32::from(name_payload.len()).serialize(wtr)?; }
wtr.write(&name_payload)?;
Ok(()) Ok(())
} }
} }
/// The name of this module. /// The name of this module.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ModuleNameSection { pub struct ModuleNameSubsection {
name: String, name: String,
} }
impl ModuleNameSection { impl ModuleNameSubsection {
/// Create a new module name section with the specified name. /// Create a new module name section with the specified name.
pub fn new<S: Into<String>>(name: S) -> ModuleNameSection { pub fn new<S: Into<String>>(name: S) -> ModuleNameSubsection {
ModuleNameSection { name: name.into() } ModuleNameSubsection { name: name.into() }
} }
/// The name of this module. /// The name of this module.
@ -109,7 +160,7 @@ impl ModuleNameSection {
} }
} }
impl Serialize for ModuleNameSection { impl Serialize for ModuleNameSubsection {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> { fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
@ -117,22 +168,22 @@ impl Serialize for ModuleNameSection {
} }
} }
impl Deserialize for ModuleNameSection { impl Deserialize for ModuleNameSubsection {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(rdr: &mut R) -> Result<ModuleNameSection, Error> { fn deserialize<R: io::Read>(rdr: &mut R) -> Result<ModuleNameSubsection, Error> {
let name = String::deserialize(rdr)?; let name = String::deserialize(rdr)?;
Ok(ModuleNameSection { name }) Ok(ModuleNameSubsection { name })
} }
} }
/// The names of the functions in this module. /// The names of the functions in this module.
#[derive(Clone, Debug, Default, PartialEq)] #[derive(Clone, Debug, Default, PartialEq)]
pub struct FunctionNameSection { pub struct FunctionNameSubsection {
names: NameMap, names: NameMap,
} }
impl FunctionNameSection { impl FunctionNameSubsection {
/// A map from function indices to names. /// A map from function indices to names.
pub fn names(&self) -> &NameMap { pub fn names(&self) -> &NameMap {
&self.names &self.names
@ -147,13 +198,13 @@ impl FunctionNameSection {
pub fn deserialize<R: io::Read>( pub fn deserialize<R: io::Read>(
module: &Module, module: &Module,
rdr: &mut R, rdr: &mut R,
) -> Result<FunctionNameSection, Error> { ) -> Result<FunctionNameSubsection, Error> {
let names = IndexMap::deserialize(module.functions_space(), rdr)?; let names = IndexMap::deserialize(module.functions_space(), rdr)?;
Ok(FunctionNameSection { names }) Ok(FunctionNameSubsection { names })
} }
} }
impl Serialize for FunctionNameSection { impl Serialize for FunctionNameSubsection {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> { fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
@ -163,11 +214,11 @@ impl Serialize for FunctionNameSection {
/// The names of the local variables in this module's functions. /// The names of the local variables in this module's functions.
#[derive(Clone, Debug, Default, PartialEq)] #[derive(Clone, Debug, Default, PartialEq)]
pub struct LocalNameSection { pub struct LocalNameSubsection {
local_names: IndexMap<NameMap>, local_names: IndexMap<NameMap>,
} }
impl LocalNameSection { impl LocalNameSubsection {
/// A map from function indices to a map from variables indices to names. /// A map from function indices to a map from variables indices to names.
pub fn local_names(&self) -> &IndexMap<NameMap> { pub fn local_names(&self) -> &IndexMap<NameMap> {
&self.local_names &self.local_names
@ -184,7 +235,7 @@ impl LocalNameSection {
pub fn deserialize<R: io::Read>( pub fn deserialize<R: io::Read>(
module: &Module, module: &Module,
rdr: &mut R, rdr: &mut R,
) -> Result<LocalNameSection, Error> { ) -> Result<LocalNameSubsection, Error> {
let funcs = module.function_section().ok_or_else(|| { let funcs = module.function_section().ok_or_else(|| {
Error::Other("cannot deserialize local names without a function section") Error::Other("cannot deserialize local names without a function section")
})?; })?;
@ -214,10 +265,10 @@ impl LocalNameSection {
&deserialize_locals, &deserialize_locals,
rdr, rdr,
)?; )?;
Ok(LocalNameSection { local_names }) Ok(LocalNameSubsection { local_names })
}} }}
impl Serialize for LocalNameSection { impl Serialize for LocalNameSubsection {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> { fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
@ -244,20 +295,20 @@ mod tests {
#[test] #[test]
fn serialize_module_name() { fn serialize_module_name() {
let original = NameSection::Module(ModuleNameSection::new("my_mod")); let original = NameSection::Module(ModuleNameSubsection::new("my_mod"));
serialize_test(original.clone()); serialize_test(original.clone());
} }
#[test] #[test]
fn serialize_function_names() { fn serialize_function_names() {
let mut sect = FunctionNameSection::default(); let mut sect = FunctionNameSubsection::default();
sect.names_mut().insert(0, "hello_world".to_string()); sect.names_mut().insert(0, "hello_world".to_string());
serialize_test(NameSection::Function(sect)); serialize_test(NameSection::Function(sect));
} }
#[test] #[test]
fn serialize_local_names() { fn serialize_local_names() {
let mut sect = LocalNameSection::default(); let mut sect = LocalNameSubsection::default();
let mut locals = NameMap::default(); let mut locals = NameMap::default();
locals.insert(0, "msg".to_string()); locals.insert(0, "msg".to_string());
sect.local_names_mut().insert(0, locals); sect.local_names_mut().insert(0, locals);