Use traps in value to convey an error

This commit is contained in:
Sergey Pepyakin 2018-01-29 17:56:59 +03:00
parent 9bce81b7a1
commit ee7ef764de
2 changed files with 19 additions and 17 deletions

View File

@ -791,7 +791,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
.map(|(left, right)| (left.transmute_into(), right.transmute_into())) .map(|(left, right)| (left.transmute_into(), right.transmute_into()))
.map(|(left, right)| left.div(right).map_err(|_| Error::Trap(Trap::DivisionByZero)))? .map(|(left, right)| left.div(right).map_err(Error::Trap))?
.map(|v| v.transmute_into()) .map(|v| v.transmute_into())
.map(|v| context.value_stack_mut().push(v.into())) .map(|v| context.value_stack_mut().push(v.into()))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
@ -803,7 +803,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
.value_stack_mut() .value_stack_mut()
.pop_pair_as::<T>() .pop_pair_as::<T>()
.map(|(left, right)| (left.transmute_into(), right.transmute_into())) .map(|(left, right)| (left.transmute_into(), right.transmute_into()))
.map(|(left, right)| left.rem(right).map_err(|_| Error::Trap(Trap::DivisionByZero)))? .map(|(left, right)| left.rem(right).map_err(Error::Trap))?
.map(|v| v.transmute_into()) .map(|v| v.transmute_into())
.map(|v| context.value_stack_mut().push(v.into())) .map(|v| context.value_stack_mut().push(v.into()))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)
@ -992,11 +992,11 @@ impl<'a, E: Externals> Interpreter<'a, E> {
} }
fn run_trunc_to_int<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error> fn run_trunc_to_int<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Error>, U: TransmuteInto<V>, { where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Trap>, U: TransmuteInto<V>, {
context context
.value_stack_mut() .value_stack_mut()
.pop_as::<T>() .pop_as::<T>()
.and_then(|v| v.try_truncate_into().map_err(|_| Error::Trap(Trap::InvalidConversionToInt))) .and_then(|v| v.try_truncate_into().map_err(Error::Trap))
.map(|v| v.transmute_into()) .map(|v| v.transmute_into())
.map(|v| context.value_stack_mut().push(v.into())) .map(|v| context.value_stack_mut().push(v.into()))
.map(|_| InstructionOutcome::RunNextInstruction) .map(|_| InstructionOutcome::RunNextInstruction)

View File

@ -1,7 +1,7 @@
use std::{i32, i64, u32, u64, f32}; use std::{i32, i64, u32, u64, f32};
use std::io; use std::io;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use Error; use {Error, Trap};
use parity_wasm::elements::ValueType; use parity_wasm::elements::ValueType;
@ -65,7 +65,7 @@ pub trait ArithmeticOps<T> {
/// Multiply two values. /// Multiply two values.
fn mul(self, other: T) -> T; fn mul(self, other: T) -> T;
/// Divide two values. /// Divide two values.
fn div(self, other: T) -> Result<T, Error>; fn div(self, other: T) -> Result<T, Trap>;
} }
/// Integer value. /// Integer value.
@ -81,7 +81,7 @@ pub trait Integer<T>: ArithmeticOps<T> {
/// Get right bit rotation result. /// Get right bit rotation result.
fn rotr(self, other: T) -> T; fn rotr(self, other: T) -> T;
/// Get division remainder. /// Get division remainder.
fn rem(self, other: T) -> Result<T, Error>; fn rem(self, other: T) -> Result<T, Trap>;
} }
/// Float-point value. /// Float-point value.
@ -263,19 +263,19 @@ impl_wrap_into!(f64, f32);
macro_rules! impl_try_truncate_into { macro_rules! impl_try_truncate_into {
($from: ident, $into: ident) => { ($from: ident, $into: ident) => {
impl TryTruncateInto<$into, Error> for $from { impl TryTruncateInto<$into, Trap> for $from {
fn try_truncate_into(self) -> Result<$into, Error> { fn try_truncate_into(self) -> Result<$into, Trap> {
// Casting from a float to an integer will round the float towards zero // Casting from a float to an integer will round the float towards zero
// NOTE: currently this will cause Undefined Behavior if the rounded value cannot be represented by the // NOTE: currently this will cause Undefined Behavior if the rounded value cannot be represented by the
// target integer type. This includes Inf and NaN. This is a bug and will be fixed. // target integer type. This includes Inf and NaN. This is a bug and will be fixed.
if self.is_nan() || self.is_infinite() { if self.is_nan() || self.is_infinite() {
return Err(Error::Value("invalid float value for this operation".into())); return Err(Trap::InvalidConversionToInt);
} }
// range check // range check
let result = self as $into; let result = self as $into;
if result as $from != self.trunc() { if result as $from != self.trunc() {
return Err(Error::Value("invalid float value for this operation".into())); return Err(Trap::InvalidConversionToInt);
} }
Ok(self as $into) Ok(self as $into)
@ -537,12 +537,14 @@ macro_rules! impl_integer_arithmetic_ops {
fn add(self, other: $type) -> $type { self.wrapping_add(other) } fn add(self, other: $type) -> $type { self.wrapping_add(other) }
fn sub(self, other: $type) -> $type { self.wrapping_sub(other) } fn sub(self, other: $type) -> $type { self.wrapping_sub(other) }
fn mul(self, other: $type) -> $type { self.wrapping_mul(other) } fn mul(self, other: $type) -> $type { self.wrapping_mul(other) }
fn div(self, other: $type) -> Result<$type, Error> { fn div(self, other: $type) -> Result<$type, Trap> {
if other == 0 { Err(Error::Value("Division by zero".to_owned())) } if other == 0 {
Err(Trap::DivisionByZero)
}
else { else {
let (result, overflow) = self.overflowing_div(other); let (result, overflow) = self.overflowing_div(other);
if overflow { if overflow {
return Err(Error::Value("Attempt to divide with overflow".to_owned())); Err(Trap::InvalidConversionToInt)
} else { } else {
Ok(result) Ok(result)
} }
@ -563,7 +565,7 @@ macro_rules! impl_float_arithmetic_ops {
fn add(self, other: $type) -> $type { self + other } fn add(self, other: $type) -> $type { self + other }
fn sub(self, other: $type) -> $type { self - other } fn sub(self, other: $type) -> $type { self - other }
fn mul(self, other: $type) -> $type { self * other } fn mul(self, other: $type) -> $type { self * other }
fn div(self, other: $type) -> Result<$type, Error> { Ok(self / other) } fn div(self, other: $type) -> Result<$type, Trap> { Ok(self / other) }
} }
} }
} }
@ -579,8 +581,8 @@ macro_rules! impl_integer {
fn count_ones(self) -> $type { self.count_ones() as $type } fn count_ones(self) -> $type { self.count_ones() as $type }
fn rotl(self, other: $type) -> $type { self.rotate_left(other as u32) } fn rotl(self, other: $type) -> $type { self.rotate_left(other as u32) }
fn rotr(self, other: $type) -> $type { self.rotate_right(other as u32) } fn rotr(self, other: $type) -> $type { self.rotate_right(other as u32) }
fn rem(self, other: $type) -> Result<$type, Error> { fn rem(self, other: $type) -> Result<$type, Trap> {
if other == 0 { Err(Error::Value("Division by zero".to_owned())) } if other == 0 { Err(Trap::DivisionByZero) }
else { Ok(self.wrapping_rem(other)) } else { Ok(self.wrapping_rem(other)) }
} }
} }