Add ARMv7 as CI test target (#186)
* Add ARMv7 as CI test target * Avoid UB in conversions from floating point When truncating floating point values to integer values, we need to avoid undefined behavior if the argument does not fit into the target type which is currently impossible using casts of primitive types. Hence, this reimplements those conversions using arbitrary precision integers and rationals from the num crate.
This commit is contained in:
parent
8dac328ea7
commit
7fe6ef4e35
|
@ -0,0 +1,2 @@
|
||||||
|
[target.armv7-unknown-linux-gnueabihf]
|
||||||
|
linker = "arm-linux-gnueabihf-gcc"
|
33
.travis.yml
33
.travis.yml
|
@ -1,25 +1,24 @@
|
||||||
dist: trusty
|
dist: xenial
|
||||||
sudo: required
|
|
||||||
language:
|
language:
|
||||||
- rust
|
- rust
|
||||||
- cpp
|
- cpp
|
||||||
rust:
|
|
||||||
- nightly
|
matrix:
|
||||||
- stable
|
fast_finish: true
|
||||||
addons:
|
include:
|
||||||
apt:
|
- rust: nightly
|
||||||
sources:
|
- rust: stable
|
||||||
- ubuntu-toolchain-r-test
|
- rust: stable
|
||||||
packages:
|
env: TARGET=armv7-unknown-linux-gnueabihf
|
||||||
- gcc-8
|
|
||||||
- g++-8
|
|
||||||
- cmake
|
|
||||||
env:
|
|
||||||
- CC=/usr/bin/gcc-8 CXX=/usr/bin/g++-8
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then rustup target add wasm32-unknown-unknown; fi
|
- 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
|
- rustup component add rustfmt
|
||||||
|
- sudo apt-get install --yes cmake
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cargo fmt --all -- --check
|
- cargo fmt --all -- --check
|
||||||
# Make sure nightly targets are not broken.
|
# 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
|
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo check --benches --manifest-path=benches/Cargo.toml; fi
|
||||||
# Make sure `no_std` version checks.
|
# Make sure `no_std` version checks.
|
||||||
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo +nightly check --no-default-features --features core; fi
|
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo +nightly check --no-default-features --features core; fi
|
||||||
- ./test.sh
|
- travis_wait 60 ./test.sh
|
||||||
- ./doc.sh
|
- ./doc.sh
|
||||||
|
|
||||||
after_success: |
|
after_success: |
|
||||||
# Build documentation and deploy it to github pages.
|
# Build documentation and deploy it to github pages.
|
||||||
[ $TRAVIS_BRANCH = master ] &&
|
[ $TRAVIS_BRANCH = master ] &&
|
||||||
|
@ -37,6 +37,7 @@ after_success: |
|
||||||
sudo pip install ghp-import &&
|
sudo pip install ghp-import &&
|
||||||
ghp-import -n target/doc &&
|
ghp-import -n target/doc &&
|
||||||
git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
|
git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
|
||||||
|
|
||||||
cache: cargo
|
cache: cargo
|
||||||
before_cache:
|
before_cache:
|
||||||
# Travis can't cache files that are not readable by "others"
|
# Travis can't cache files that are not readable by "others"
|
||||||
|
|
|
@ -15,6 +15,8 @@ wasmi-validation = { version = "0.1", path = "validation", default-features = fa
|
||||||
parity-wasm = { version = "0.31", default-features = false }
|
parity-wasm = { version = "0.31", default-features = false }
|
||||||
memory_units = "0.3.0"
|
memory_units = "0.3.0"
|
||||||
libm = { version = "0.1.2", optional = true }
|
libm = { version = "0.1.2", optional = true }
|
||||||
|
num-rational = "0.2.2"
|
||||||
|
num-traits = "0.2.8"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.1"
|
assert_matches = "1.1"
|
||||||
|
@ -27,6 +29,8 @@ default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
"parity-wasm/std",
|
"parity-wasm/std",
|
||||||
"wasmi-validation/std",
|
"wasmi-validation/std",
|
||||||
|
"num-rational/std",
|
||||||
|
"num-traits/std"
|
||||||
]
|
]
|
||||||
# Enable for no_std support
|
# Enable for no_std support
|
||||||
core = [
|
core = [
|
||||||
|
|
|
@ -128,6 +128,9 @@ use std::error;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
extern crate libm;
|
extern crate libm;
|
||||||
|
|
||||||
|
extern crate num_rational;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
/// Error type which can be thrown by wasm code or by host environment.
|
/// 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.
|
/// Under some conditions, wasm execution may produce a `Trap`, which immediately aborts execution.
|
||||||
|
|
53
src/value.rs
53
src/value.rs
|
@ -366,27 +366,18 @@ impl WrapInto<F32> for F64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_try_truncate_into {
|
macro_rules! impl_try_truncate_into {
|
||||||
($from: ident, $into: ident) => {
|
(@primitive $from: ident, $into: ident, $to_primitive:path) => {
|
||||||
impl TryTruncateInto<$into, TrapKind> for $from {
|
impl TryTruncateInto<$into, TrapKind> for $from {
|
||||||
fn try_truncate_into(self) -> Result<$into, TrapKind> {
|
fn try_truncate_into(self) -> Result<$into, TrapKind> {
|
||||||
// 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
|
num_rational::BigRational::from_float(self)
|
||||||
// target integer type. This includes Inf and NaN. This is a bug and will be fixed.
|
.map(|val| val.to_integer())
|
||||||
if self.is_nan() || self.is_infinite() {
|
.and_then(|val| $to_primitive(&val))
|
||||||
return Err(TrapKind::InvalidConversionToInt);
|
.ok_or(TrapKind::InvalidConversionToInt)
|
||||||
}
|
|
||||||
|
|
||||||
// range check
|
|
||||||
let result = self as $into;
|
|
||||||
if result as $from != self.trunc() {
|
|
||||||
return Err(TrapKind::InvalidConversionToInt);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self as $into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($from:ident, $intermediate:ident, $into:ident) => {
|
(@wrapped $from:ident, $intermediate:ident, $into:ident) => {
|
||||||
impl TryTruncateInto<$into, TrapKind> for $from {
|
impl TryTruncateInto<$into, TrapKind> for $from {
|
||||||
fn try_truncate_into(self) -> Result<$into, TrapKind> {
|
fn try_truncate_into(self) -> Result<$into, TrapKind> {
|
||||||
$intermediate::from(self).try_truncate_into()
|
$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!(@primitive f32, i32, num_traits::cast::ToPrimitive::to_i32);
|
||||||
impl_try_truncate_into!(f32, i64);
|
impl_try_truncate_into!(@primitive f32, i64, num_traits::cast::ToPrimitive::to_i64);
|
||||||
impl_try_truncate_into!(f64, i32);
|
impl_try_truncate_into!(@primitive f64, i32, num_traits::cast::ToPrimitive::to_i32);
|
||||||
impl_try_truncate_into!(f64, i64);
|
impl_try_truncate_into!(@primitive f64, i64, num_traits::cast::ToPrimitive::to_i64);
|
||||||
impl_try_truncate_into!(f32, u32);
|
impl_try_truncate_into!(@primitive f32, u32, num_traits::cast::ToPrimitive::to_u32);
|
||||||
impl_try_truncate_into!(f32, u64);
|
impl_try_truncate_into!(@primitive f32, u64, num_traits::cast::ToPrimitive::to_u64);
|
||||||
impl_try_truncate_into!(f64, u32);
|
impl_try_truncate_into!(@primitive f64, u32, num_traits::cast::ToPrimitive::to_u32);
|
||||||
impl_try_truncate_into!(f64, u64);
|
impl_try_truncate_into!(@primitive f64, u64, num_traits::cast::ToPrimitive::to_u64);
|
||||||
impl_try_truncate_into!(F32, f32, i32);
|
impl_try_truncate_into!(@wrapped F32, f32, i32);
|
||||||
impl_try_truncate_into!(F32, f32, i64);
|
impl_try_truncate_into!(@wrapped F32, f32, i64);
|
||||||
impl_try_truncate_into!(F64, f64, i32);
|
impl_try_truncate_into!(@wrapped F64, f64, i32);
|
||||||
impl_try_truncate_into!(F64, f64, i64);
|
impl_try_truncate_into!(@wrapped F64, f64, i64);
|
||||||
impl_try_truncate_into!(F32, f32, u32);
|
impl_try_truncate_into!(@wrapped F32, f32, u32);
|
||||||
impl_try_truncate_into!(F32, f32, u64);
|
impl_try_truncate_into!(@wrapped F32, f32, u64);
|
||||||
impl_try_truncate_into!(F64, f64, u32);
|
impl_try_truncate_into!(@wrapped F64, f64, u32);
|
||||||
impl_try_truncate_into!(F64, f64, u64);
|
impl_try_truncate_into!(@wrapped F64, f64, u64);
|
||||||
|
|
||||||
macro_rules! impl_extend_into {
|
macro_rules! impl_extend_into {
|
||||||
($from:ident, $into:ident) => {
|
($from:ident, $into:ident) => {
|
||||||
|
|
12
test.sh
12
test.sh
|
@ -2,8 +2,18 @@
|
||||||
|
|
||||||
set -eux
|
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)
|
cd $(dirname $0)
|
||||||
|
|
||||||
time cargo test --all
|
time cargo test --all ${EXTRA_ARGS}
|
||||||
|
|
||||||
cd -
|
cd -
|
||||||
|
|
Loading…
Reference in New Issue