mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-24 22:21:32 +00:00
feat(decoders) Improve LEB parser in the binary
module.
The LEB parser is renamed `uleb`. It now checks for overflow, and badly-formed bits, resp. `TooLarge` or `Eof`. More test cases are added, whose from the DWARF 4 standard.
This commit is contained in:
@ -53,15 +53,18 @@ fn byte<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'i
|
|||||||
|
|
||||||
/// Parse an unsigned Little Endian Based (LEB) with value no larger
|
/// Parse an unsigned Little Endian Based (LEB) with value no larger
|
||||||
/// than a 64-bits number. Read
|
/// than a 64-bits number. Read
|
||||||
/// [LEB128](https://en.wikipedia.org/wiki/LEB128) to learn more.
|
/// [LEB128](https://en.wikipedia.org/wiki/LEB128) to learn more, or
|
||||||
fn leb<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'input [u8], u64, E> {
|
/// the Variable Length Data Section from the [DWARF 4
|
||||||
|
/// standard](http://dwarfstd.org/doc/DWARF4.pdf).
|
||||||
|
fn uleb<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'input [u8], u64, E> {
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
|
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (output, bytes) = match input.iter().position(|&byte| byte & 0x80 == 0) {
|
let (output, bytes) = match dbg!(input.iter().position(|&byte| byte & 0x80 == 0)) {
|
||||||
Some(position) => (&input[position + 1..], &input[..=position]),
|
Some(length) if length <= 8 => (&input[length + 1..], &input[..=length]),
|
||||||
None => (&[] as &[u8], input),
|
Some(_) => return Err(Err::Error(make_error(input, ErrorKind::TooLarge))),
|
||||||
|
None => return Err(Err::Error(make_error(input, ErrorKind::Eof))),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
@ -128,7 +131,7 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
|
|||||||
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
|
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (output, ty) = leb(input)?;
|
let (output, ty) = uleb(input)?;
|
||||||
|
|
||||||
match InterfaceType::try_from(ty) {
|
match InterfaceType::try_from(ty) {
|
||||||
Ok(ty) => Ok((output, ty)),
|
Ok(ty) => Ok((output, ty)),
|
||||||
@ -144,12 +147,12 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
|||||||
|
|
||||||
Ok(match opcode {
|
Ok(match opcode {
|
||||||
0x00 => {
|
0x00 => {
|
||||||
consume!((input, argument_0) = leb(input)?);
|
consume!((input, argument_0) = uleb(input)?);
|
||||||
(input, Instruction::ArgumentGet { index: argument_0 })
|
(input, Instruction::ArgumentGet { index: argument_0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
0x01 => {
|
0x01 => {
|
||||||
consume!((input, argument_0) = leb(input)?);
|
consume!((input, argument_0) = uleb(input)?);
|
||||||
(
|
(
|
||||||
input,
|
input,
|
||||||
Instruction::Call {
|
Instruction::Call {
|
||||||
@ -195,7 +198,7 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
|||||||
0x08 => (input, Instruction::TableRefGet),
|
0x08 => (input, Instruction::TableRefGet),
|
||||||
|
|
||||||
0x09 => {
|
0x09 => {
|
||||||
consume!((input, argument_0) = leb(input)?);
|
consume!((input, argument_0) = uleb(input)?);
|
||||||
(input, Instruction::CallMethod(argument_0))
|
(input, Instruction::CallMethod(argument_0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,18 +209,18 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
|||||||
|
|
||||||
0x0c => {
|
0x0c => {
|
||||||
consume!((input, argument_0) = ty(input)?);
|
consume!((input, argument_0) = ty(input)?);
|
||||||
consume!((input, argument_1) = leb(input)?);
|
consume!((input, argument_1) = uleb(input)?);
|
||||||
(input, Instruction::GetField(argument_0, argument_1))
|
(input, Instruction::GetField(argument_0, argument_1))
|
||||||
}
|
}
|
||||||
|
|
||||||
0x0d => {
|
0x0d => {
|
||||||
consume!((input, argument_0) = ty(input)?);
|
consume!((input, argument_0) = ty(input)?);
|
||||||
consume!((input, argument_1) = leb(input)?);
|
consume!((input, argument_1) = uleb(input)?);
|
||||||
(input, Instruction::Const(argument_0, argument_1))
|
(input, Instruction::Const(argument_0, argument_1))
|
||||||
}
|
}
|
||||||
|
|
||||||
0x0e => {
|
0x0e => {
|
||||||
consume!((input, argument_0) = leb(input)?);
|
consume!((input, argument_0) = uleb(input)?);
|
||||||
(input, Instruction::FoldSeq(argument_0))
|
(input, Instruction::FoldSeq(argument_0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,8 +249,8 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
|||||||
0x13 => (input, Instruction::ListPush),
|
0x13 => (input, Instruction::ListPush),
|
||||||
|
|
||||||
0x14 => {
|
0x14 => {
|
||||||
consume!((input, argument_0) = leb(input)?);
|
consume!((input, argument_0) = uleb(input)?);
|
||||||
consume!((input, argument_1) = leb(input)?);
|
consume!((input, argument_1) = uleb(input)?);
|
||||||
(input, Instruction::RepeatUntil(argument_0, argument_1))
|
(input, Instruction::RepeatUntil(argument_0, argument_1))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +264,7 @@ fn exports<'input, E: ParseError<&'input [u8]>>(
|
|||||||
) -> IResult<&'input [u8], Vec<Export>, E> {
|
) -> IResult<&'input [u8], Vec<Export>, E> {
|
||||||
let mut input = input;
|
let mut input = input;
|
||||||
|
|
||||||
consume!((input, number_of_exports) = leb(input)?);
|
consume!((input, number_of_exports) = uleb(input)?);
|
||||||
|
|
||||||
let mut exports = Vec::with_capacity(number_of_exports as usize);
|
let mut exports = Vec::with_capacity(number_of_exports as usize);
|
||||||
|
|
||||||
@ -286,7 +289,7 @@ fn types<'input, E: ParseError<&'input [u8]>>(
|
|||||||
) -> IResult<&'input [u8], Vec<Type>, E> {
|
) -> IResult<&'input [u8], Vec<Type>, E> {
|
||||||
let mut input = input;
|
let mut input = input;
|
||||||
|
|
||||||
consume!((input, number_of_types) = leb(input)?);
|
consume!((input, number_of_types) = uleb(input)?);
|
||||||
|
|
||||||
let mut types = Vec::with_capacity(number_of_types as usize);
|
let mut types = Vec::with_capacity(number_of_types as usize);
|
||||||
|
|
||||||
@ -307,7 +310,7 @@ fn imports<'input, E: ParseError<&'input [u8]>>(
|
|||||||
) -> IResult<&'input [u8], Vec<Import>, E> {
|
) -> IResult<&'input [u8], Vec<Import>, E> {
|
||||||
let mut input = input;
|
let mut input = input;
|
||||||
|
|
||||||
consume!((input, number_of_imports) = leb(input)?);
|
consume!((input, number_of_imports) = uleb(input)?);
|
||||||
|
|
||||||
let mut imports = Vec::with_capacity(number_of_imports as usize);
|
let mut imports = Vec::with_capacity(number_of_imports as usize);
|
||||||
|
|
||||||
@ -334,7 +337,7 @@ fn adapters<'input, E: ParseError<&'input [u8]>>(
|
|||||||
) -> IResult<&'input [u8], Vec<Adapter>, E> {
|
) -> IResult<&'input [u8], Vec<Adapter>, E> {
|
||||||
let mut input = input;
|
let mut input = input;
|
||||||
|
|
||||||
consume!((input, number_of_adapters) = leb(input)?);
|
consume!((input, number_of_adapters) = uleb(input)?);
|
||||||
|
|
||||||
let mut adapters = Vec::with_capacity(number_of_adapters as usize);
|
let mut adapters = Vec::with_capacity(number_of_adapters as usize);
|
||||||
|
|
||||||
@ -399,7 +402,7 @@ fn forwards<'input, E: ParseError<&'input [u8]>>(
|
|||||||
) -> IResult<&'input [u8], Vec<Forward>, E> {
|
) -> IResult<&'input [u8], Vec<Forward>, E> {
|
||||||
let mut input = input;
|
let mut input = input;
|
||||||
|
|
||||||
consume!((input, number_of_forwards) = leb(input)?);
|
consume!((input, number_of_forwards) = uleb(input)?);
|
||||||
|
|
||||||
let mut forwards = Vec::with_capacity(number_of_forwards as usize);
|
let mut forwards = Vec::with_capacity(number_of_forwards as usize);
|
||||||
|
|
||||||
@ -528,6 +531,7 @@ pub fn parse<'input, E: ParseError<&'input [u8]>>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use nom::{error, Err};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_byte() {
|
fn test_byte() {
|
||||||
@ -538,19 +542,68 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_leb_1_byte() {
|
fn test_uleb_1_byte() {
|
||||||
let input = &[0x01, 0x02, 0x03];
|
let input = &[0x01, 0x02, 0x03];
|
||||||
let output = Ok((&[0x02, 0x03][..], 0x01u64));
|
let output = Ok((&[0x02, 0x03][..], 0x01u64));
|
||||||
|
|
||||||
assert_eq!(leb::<()>(input), output);
|
assert_eq!(uleb::<()>(input), output);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_leb_3_bytes() {
|
fn test_uleb_3_bytes() {
|
||||||
let input = &[0xfc, 0xff, 0x01, 0x02];
|
let input = &[0xfc, 0xff, 0x01, 0x02];
|
||||||
let output = Ok((&[0x02][..], 0x7ffcu64));
|
let output = Ok((&[0x02][..], 0x7ffcu64));
|
||||||
|
|
||||||
assert_eq!(leb::<()>(input), output);
|
assert_eq!(uleb::<()>(input), output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Examples from Figure 22 of [DWARF 4
|
||||||
|
// standard](http://dwarfstd.org/doc/DWARF4.pdf).
|
||||||
|
#[test]
|
||||||
|
fn test_uleb_from_dwarf_standard() {
|
||||||
|
macro_rules! assert_uleb {
|
||||||
|
($to_parse:expr => $expected_result:expr) => {
|
||||||
|
assert_eq!(uleb::<()>($to_parse), Ok((&[][..], $expected_result)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_uleb!(&[2u8] => 2u64);
|
||||||
|
assert_uleb!(&[127u8] => 127u64);
|
||||||
|
assert_uleb!(&[0x80, 1u8] => 128u64);
|
||||||
|
assert_uleb!(&[1u8 | 0x80, 1] => 129u64);
|
||||||
|
assert_uleb!(&[2u8 | 0x80, 1] => 130u64);
|
||||||
|
assert_uleb!(&[57u8 | 0x80, 100] => 12857u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uleb_eof() {
|
||||||
|
let input = &[0x80];
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
uleb::<(&[u8], error::ErrorKind)>(input),
|
||||||
|
Err(Err::Error((&input[..], error::ErrorKind::Eof))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uleb_overflow() {
|
||||||
|
let input = &[
|
||||||
|
0x01 | 0x80,
|
||||||
|
0x02 | 0x80,
|
||||||
|
0x03 | 0x80,
|
||||||
|
0x04 | 0x80,
|
||||||
|
0x05 | 0x80,
|
||||||
|
0x06 | 0x80,
|
||||||
|
0x07 | 0x80,
|
||||||
|
0x08 | 0x80,
|
||||||
|
0x09 | 0x80,
|
||||||
|
0x0a,
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
uleb::<(&[u8], error::ErrorKind)>(input),
|
||||||
|
Err(Err::Error((&input[..], error::ErrorKind::TooLarge))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Reference in New Issue
Block a user