Use transmute instead of casts In RuntimeValue conversion. (#102)

Casts have arithmetic semantics, and under some build configurations
Rust will panic when encountering an arithmetic overflow.
Use a transmute instead since it's what we mean.
The previous code worked, but still I added a test for good measure.
This commit is contained in:
Leonardo Yvens 2018-06-21 09:47:49 -03:00 committed by Sergey Pepyakin
parent 94b797de44
commit 75406dd8ff
2 changed files with 24 additions and 5 deletions

View File

@ -17,6 +17,19 @@ fn assert_error_properties() {
assert_std_err_impl::<Error>(); assert_std_err_impl::<Error>();
} }
/// Test that converting an u32 (u64) that does not fit in an i32 (i64)
/// to a RuntimeValue and back works as expected and the number remains unchanged.
#[test]
fn unsigned_to_runtime_value() {
use super::RuntimeValue;
let overflow_i32: u32 = ::std::i32::MAX as u32 + 1;
assert_eq!(RuntimeValue::from(overflow_i32).try_into::<u32>().unwrap(), overflow_i32);
let overflow_i64: u64 = ::std::i64::MAX as u64 + 1;
assert_eq!(RuntimeValue::from(overflow_i64).try_into::<u64>().unwrap(), overflow_i64);
}
pub fn parse_wat(source: &str) -> Module { pub fn parse_wat(source: &str) -> Module {
let wasm_binary = wabt::wat2wasm(source).expect("Failed to parse wat source"); let wasm_binary = wabt::wat2wasm(source).expect("Failed to parse wat source");
Module::from_buffer(wasm_binary).expect("Failed to load parsed module") Module::from_buffer(wasm_binary).expect("Failed to load parsed module")

View File

@ -1,6 +1,7 @@
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use nan_preserving_float::{F32, F64}; use nan_preserving_float::{F32, F64};
use std::io; use std::io;
use std::mem::transmute;
use std::{f32, i32, i64, u32, u64}; use std::{f32, i32, i64, u32, u64};
use TrapKind; use TrapKind;
@ -188,13 +189,13 @@ impl From<i64> for RuntimeValue {
impl From<u32> for RuntimeValue { impl From<u32> for RuntimeValue {
fn from(val: u32) -> Self { fn from(val: u32) -> Self {
RuntimeValue::I32(val as i32) RuntimeValue::I32(val.transmute_into())
} }
} }
impl From<u64> for RuntimeValue { impl From<u64> for RuntimeValue {
fn from(val: u64) -> Self { fn from(val: u64) -> Self {
RuntimeValue::I64(val as i64) RuntimeValue::I64(val.transmute_into())
} }
} }
@ -403,11 +404,8 @@ macro_rules! impl_transmute_into_as {
} }
impl_transmute_into_as!(i8, u8); impl_transmute_into_as!(i8, u8);
impl_transmute_into_as!(u8, i8);
impl_transmute_into_as!(i32, u32); impl_transmute_into_as!(i32, u32);
impl_transmute_into_as!(u32, i32);
impl_transmute_into_as!(i64, u64); impl_transmute_into_as!(i64, u64);
impl_transmute_into_as!(u64, i64);
macro_rules! impl_transmute_into_npf { macro_rules! impl_transmute_into_npf {
($npf:ident, $float:ident, $signed:ident, $unsigned:ident) => { ($npf:ident, $float:ident, $signed:ident, $unsigned:ident) => {
@ -468,6 +466,14 @@ impl TransmuteInto<f64> for i64 {
fn transmute_into(self) -> f64 { f64::from_bits(self as u64) } fn transmute_into(self) -> f64 { f64::from_bits(self as u64) }
} }
impl TransmuteInto<i32> for u32 {
fn transmute_into(self) -> i32 { unsafe { transmute(self) } }
}
impl TransmuteInto<i64> for u64 {
fn transmute_into(self) -> i64 { unsafe { transmute(self) } }
}
impl LittleEndianConvert for i8 { impl LittleEndianConvert for i8 {
fn into_little_endian(self) -> Vec<u8> { fn into_little_endian(self) -> Vec<u8> {
vec![self as u8] vec![self as u8]