rustc_serialize: fix incorrect signed LEB128 decoding
The signed LEB128 decoding function used a hardcoded constant of 64 instead of the number of bits in the type of integer being decoded, which resulted in incorrect results for some inputs. Fix this, make the decoding more consistent with the unsigned version, and increase the LEB128 encoding and decoding test coverage.
This commit is contained in:
parent
52f21791fb
commit
f15fae822e
4 changed files with 88 additions and 57 deletions
|
@ -119,28 +119,38 @@ impl_write_signed_leb128!(write_i64_leb128, i64);
|
|||
impl_write_signed_leb128!(write_i128_leb128, i128);
|
||||
impl_write_signed_leb128!(write_isize_leb128, isize);
|
||||
|
||||
#[inline]
|
||||
pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) {
|
||||
let mut result = 0;
|
||||
let mut shift = 0;
|
||||
let mut position = start_position;
|
||||
let mut byte;
|
||||
macro_rules! impl_read_signed_leb128 {
|
||||
($fn_name:ident, $int_ty:ty) => {
|
||||
#[inline]
|
||||
pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
|
||||
let mut result = 0;
|
||||
let mut shift = 0;
|
||||
let mut position = 0;
|
||||
let mut byte;
|
||||
|
||||
loop {
|
||||
byte = data[position];
|
||||
position += 1;
|
||||
result |= i128::from(byte & 0x7F) << shift;
|
||||
shift += 7;
|
||||
loop {
|
||||
byte = slice[position];
|
||||
position += 1;
|
||||
result |= <$int_ty>::from(byte & 0x7F) << shift;
|
||||
shift += 7;
|
||||
|
||||
if (byte & 0x80) == 0 {
|
||||
break;
|
||||
if (byte & 0x80) == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shift < <$int_ty>::BITS) && ((byte & 0x40) != 0) {
|
||||
// sign extend
|
||||
result |= (!0 << shift);
|
||||
}
|
||||
|
||||
(result, position)
|
||||
}
|
||||
}
|
||||
|
||||
if (shift < 64) && ((byte & 0x40) != 0) {
|
||||
// sign extend
|
||||
result |= -(1 << shift);
|
||||
}
|
||||
|
||||
(result, position - start_position)
|
||||
};
|
||||
}
|
||||
|
||||
impl_read_signed_leb128!(read_i16_leb128, i16);
|
||||
impl_read_signed_leb128!(read_i32_leb128, i32);
|
||||
impl_read_signed_leb128!(read_i64_leb128, i64);
|
||||
impl_read_signed_leb128!(read_i128_leb128, i128);
|
||||
impl_read_signed_leb128!(read_isize_leb128, isize);
|
||||
|
|
|
@ -17,6 +17,7 @@ Core encoding and decoding interfaces.
|
|||
#![feature(min_specialization)]
|
||||
#![feature(vec_spare_capacity)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(int_bits_const)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(new_uninit)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::leb128::{self, max_leb128_len, read_signed_leb128};
|
||||
use crate::leb128::{self, max_leb128_len};
|
||||
use crate::serialize;
|
||||
use std::borrow::Cow;
|
||||
use std::fs::File;
|
||||
|
@ -561,7 +561,7 @@ impl<'a> Decoder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! read_uleb128 {
|
||||
macro_rules! read_leb128 {
|
||||
($dec:expr, $fun:ident) => {{
|
||||
let (value, bytes_read) = leb128::$fun(&$dec.data[$dec.position..]);
|
||||
$dec.position += bytes_read;
|
||||
|
@ -569,14 +569,6 @@ macro_rules! read_uleb128 {
|
|||
}};
|
||||
}
|
||||
|
||||
macro_rules! read_sleb128 {
|
||||
($dec:expr, $t:ty) => {{
|
||||
let (value, bytes_read) = read_signed_leb128($dec.data, $dec.position);
|
||||
$dec.position += bytes_read;
|
||||
Ok(value as $t)
|
||||
}};
|
||||
}
|
||||
|
||||
impl<'a> serialize::Decoder for Decoder<'a> {
|
||||
type Error = String;
|
||||
|
||||
|
@ -587,22 +579,22 @@ impl<'a> serialize::Decoder for Decoder<'a> {
|
|||
|
||||
#[inline]
|
||||
fn read_u128(&mut self) -> Result<u128, Self::Error> {
|
||||
read_uleb128!(self, read_u128_leb128)
|
||||
read_leb128!(self, read_u128_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
read_uleb128!(self, read_u64_leb128)
|
||||
read_leb128!(self, read_u64_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_u32(&mut self) -> Result<u32, Self::Error> {
|
||||
read_uleb128!(self, read_u32_leb128)
|
||||
read_leb128!(self, read_u32_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_u16(&mut self) -> Result<u16, Self::Error> {
|
||||
read_uleb128!(self, read_u16_leb128)
|
||||
read_leb128!(self, read_u16_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -614,27 +606,27 @@ impl<'a> serialize::Decoder for Decoder<'a> {
|
|||
|
||||
#[inline]
|
||||
fn read_usize(&mut self) -> Result<usize, Self::Error> {
|
||||
read_uleb128!(self, read_usize_leb128)
|
||||
read_leb128!(self, read_usize_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_i128(&mut self) -> Result<i128, Self::Error> {
|
||||
read_sleb128!(self, i128)
|
||||
read_leb128!(self, read_i128_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_i64(&mut self) -> Result<i64, Self::Error> {
|
||||
read_sleb128!(self, i64)
|
||||
read_leb128!(self, read_i64_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_i32(&mut self) -> Result<i32, Self::Error> {
|
||||
read_sleb128!(self, i32)
|
||||
read_leb128!(self, read_i32_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_i16(&mut self) -> Result<i16, Self::Error> {
|
||||
read_sleb128!(self, i16)
|
||||
read_leb128!(self, read_i16_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -646,7 +638,7 @@ impl<'a> serialize::Decoder for Decoder<'a> {
|
|||
|
||||
#[inline]
|
||||
fn read_isize(&mut self) -> Result<isize, Self::Error> {
|
||||
read_sleb128!(self, isize)
|
||||
read_leb128!(self, read_isize_leb128)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue