diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..0c1c209 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[target.armv7-unknown-linux-gnueabihf] +linker = "arm-linux-gnueabihf-gcc" diff --git a/.travis.yml b/.travis.yml index e54d69d..7336c16 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,25 +1,24 @@ -dist: trusty -sudo: required +dist: xenial + language: - rust - cpp -rust: - - nightly - - stable -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-8 - - g++-8 - - cmake -env: -- CC=/usr/bin/gcc-8 CXX=/usr/bin/g++-8 + +matrix: + fast_finish: true + include: + - rust: nightly + - rust: stable + - rust: stable + env: TARGET=armv7-unknown-linux-gnueabihf install: - if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then rustup target add wasm32-unknown-unknown; fi +- if [ -n "$TARGET" ]; then rustup target add "$TARGET" && sudo apt-get install --yes qemu-user-static; fi +- if [ "$TARGET" == "armv7-unknown-linux-gnueabihf" ]; then sudo apt-get install --yes crossbuild-essential-armhf && export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf; fi - rustup component add rustfmt +- sudo apt-get install --yes cmake + script: - cargo fmt --all -- --check # Make sure nightly targets are not broken. @@ -27,8 +26,9 @@ script: - if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo check --benches --manifest-path=benches/Cargo.toml; fi # Make sure `no_std` version checks. - if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo +nightly check --no-default-features --features core; fi -- ./test.sh +- travis_wait 60 ./test.sh - ./doc.sh + after_success: | # Build documentation and deploy it to github pages. [ $TRAVIS_BRANCH = master ] && @@ -37,6 +37,7 @@ after_success: | sudo pip install ghp-import && ghp-import -n target/doc && git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages + cache: cargo before_cache: # Travis can't cache files that are not readable by "others" diff --git a/Cargo.toml b/Cargo.toml index e9e01e5..a75cfbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,8 @@ wasmi-validation = { version = "0.1", path = "validation", default-features = fa parity-wasm = { version = "0.31", default-features = false } memory_units = "0.3.0" libm = { version = "0.1.2", optional = true } +num-rational = "0.2.2" +num-traits = "0.2.8" [dev-dependencies] assert_matches = "1.1" @@ -27,6 +29,8 @@ default = ["std"] std = [ "parity-wasm/std", "wasmi-validation/std", + "num-rational/std", + "num-traits/std" ] # Enable for no_std support core = [ diff --git a/src/lib.rs b/src/lib.rs index ccbc90a..9384147 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,6 +128,9 @@ use std::error; #[cfg(not(feature = "std"))] extern crate libm; +extern crate num_rational; +extern crate num_traits; + /// Error type which can be thrown by wasm code or by host environment. /// /// Under some conditions, wasm execution may produce a `Trap`, which immediately aborts execution. diff --git a/src/value.rs b/src/value.rs index 9891923..8d5061a 100644 --- a/src/value.rs +++ b/src/value.rs @@ -366,27 +366,18 @@ impl WrapInto for F64 { } macro_rules! impl_try_truncate_into { - ($from: ident, $into: ident) => { + (@primitive $from: ident, $into: ident, $to_primitive:path) => { impl TryTruncateInto<$into, TrapKind> for $from { fn try_truncate_into(self) -> Result<$into, TrapKind> { // 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 - // target integer type. This includes Inf and NaN. This is a bug and will be fixed. - if self.is_nan() || self.is_infinite() { - return Err(TrapKind::InvalidConversionToInt); - } - - // range check - let result = self as $into; - if result as $from != self.trunc() { - return Err(TrapKind::InvalidConversionToInt); - } - - Ok(self as $into) + num_rational::BigRational::from_float(self) + .map(|val| val.to_integer()) + .and_then(|val| $to_primitive(&val)) + .ok_or(TrapKind::InvalidConversionToInt) } } }; - ($from:ident, $intermediate:ident, $into:ident) => { + (@wrapped $from:ident, $intermediate:ident, $into:ident) => { impl TryTruncateInto<$into, TrapKind> for $from { fn try_truncate_into(self) -> Result<$into, TrapKind> { $intermediate::from(self).try_truncate_into() @@ -395,22 +386,22 @@ macro_rules! impl_try_truncate_into { }; } -impl_try_truncate_into!(f32, i32); -impl_try_truncate_into!(f32, i64); -impl_try_truncate_into!(f64, i32); -impl_try_truncate_into!(f64, i64); -impl_try_truncate_into!(f32, u32); -impl_try_truncate_into!(f32, u64); -impl_try_truncate_into!(f64, u32); -impl_try_truncate_into!(f64, u64); -impl_try_truncate_into!(F32, f32, i32); -impl_try_truncate_into!(F32, f32, i64); -impl_try_truncate_into!(F64, f64, i32); -impl_try_truncate_into!(F64, f64, i64); -impl_try_truncate_into!(F32, f32, u32); -impl_try_truncate_into!(F32, f32, u64); -impl_try_truncate_into!(F64, f64, u32); -impl_try_truncate_into!(F64, f64, u64); +impl_try_truncate_into!(@primitive f32, i32, num_traits::cast::ToPrimitive::to_i32); +impl_try_truncate_into!(@primitive f32, i64, num_traits::cast::ToPrimitive::to_i64); +impl_try_truncate_into!(@primitive f64, i32, num_traits::cast::ToPrimitive::to_i32); +impl_try_truncate_into!(@primitive f64, i64, num_traits::cast::ToPrimitive::to_i64); +impl_try_truncate_into!(@primitive f32, u32, num_traits::cast::ToPrimitive::to_u32); +impl_try_truncate_into!(@primitive f32, u64, num_traits::cast::ToPrimitive::to_u64); +impl_try_truncate_into!(@primitive f64, u32, num_traits::cast::ToPrimitive::to_u32); +impl_try_truncate_into!(@primitive f64, u64, num_traits::cast::ToPrimitive::to_u64); +impl_try_truncate_into!(@wrapped F32, f32, i32); +impl_try_truncate_into!(@wrapped F32, f32, i64); +impl_try_truncate_into!(@wrapped F64, f64, i32); +impl_try_truncate_into!(@wrapped F64, f64, i64); +impl_try_truncate_into!(@wrapped F32, f32, u32); +impl_try_truncate_into!(@wrapped F32, f32, u64); +impl_try_truncate_into!(@wrapped F64, f64, u32); +impl_try_truncate_into!(@wrapped F64, f64, u64); macro_rules! impl_extend_into { ($from:ident, $into:ident) => { diff --git a/test.sh b/test.sh index 4ee4c32..2240728 100755 --- a/test.sh +++ b/test.sh @@ -2,8 +2,18 @@ set -eux +EXTRA_ARGS="" + +if [ -n "${TARGET-}" ]; then + # Tests build in debug mode are prohibitively + # slow when ran under emulation so that + # e.g. Travis CI will hit timeouts. + EXTRA_ARGS="--release --target=${TARGET}" + export RUSTFLAGS="--cfg debug_assertions" +fi + cd $(dirname $0) -time cargo test --all +time cargo test --all ${EXTRA_ARGS} cd -