Update lifting for integers and bools (#4237)

This commit updates lifting for integer types and boolean types to
account for WebAssembly/component-model#35 where extra bits are now
discarded instead of being validated as all zero.
This commit is contained in:
Alex Crichton
2022-06-07 12:51:32 -05:00
committed by GitHub
parent 11ff9650e5
commit 479def00b9
2 changed files with 42 additions and 64 deletions

View File

@@ -712,11 +712,7 @@ macro_rules! integers {
unsafe impl Lift for $primitive { unsafe impl Lift for $primitive {
#[inline] #[inline]
fn lift(_store: &StoreOpaque, _options: &Options, src: &Self::Lower) -> Result<Self> { fn lift(_store: &StoreOpaque, _options: &Options, src: &Self::Lower) -> Result<Self> {
// Perform a lossless cast from our field storage to the Ok(src.$get() as $primitive)
// destination type. Note that `try_from` here is load bearing
// which rejects conversions like `500u32` to `u8` because
// that's out-of-bounds for `u8`.
Ok($primitive::try_from(src.$get())?)
} }
#[inline] #[inline]
@@ -852,8 +848,7 @@ unsafe impl Lift for bool {
fn lift(_store: &StoreOpaque, _options: &Options, src: &Self::Lower) -> Result<Self> { fn lift(_store: &StoreOpaque, _options: &Options, src: &Self::Lower) -> Result<Self> {
match src.get_i32() { match src.get_i32() {
0 => Ok(false), 0 => Ok(false),
1 => Ok(true), _ => Ok(true),
_ => bail!("invalid boolean value"),
} }
} }
@@ -861,8 +856,7 @@ unsafe impl Lift for bool {
fn load(_mem: &Memory<'_>, bytes: &[u8]) -> Result<Self> { fn load(_mem: &Memory<'_>, bytes: &[u8]) -> Result<Self> {
match bytes[0] { match bytes[0] {
0 => Ok(false), 0 => Ok(false),
1 => Ok(true), _ => Ok(true),
_ => bail!("invalid boolean value"),
} }
} }
} }

View File

@@ -364,15 +364,12 @@ fn integers() -> Result<()> {
0 0
); );
// Returning -1 should fail for u8 and u16, but succeed for all other types. // Returning -1 should reinterpret the bytes as defined by each type.
let err = instance assert_eq!(
instance
.get_typed_func::<(), u8, _>(&mut store, "retm1-u8")? .get_typed_func::<(), u8, _>(&mut store, "retm1-u8")?
.call(&mut store, ()) .call(&mut store, ())?,
.unwrap_err(); 0xff
assert!(
err.to_string().contains("out of range integral type"),
"{}",
err
); );
assert_eq!( assert_eq!(
instance instance
@@ -380,14 +377,11 @@ fn integers() -> Result<()> {
.call(&mut store, ())?, .call(&mut store, ())?,
-1 -1
); );
let err = instance assert_eq!(
instance
.get_typed_func::<(), u16, _>(&mut store, "retm1-u16")? .get_typed_func::<(), u16, _>(&mut store, "retm1-u16")?
.call(&mut store, ()) .call(&mut store, ())?,
.unwrap_err(); 0xffff
assert!(
err.to_string().contains("out of range integral type"),
"{}",
err
); );
assert_eq!( assert_eq!(
instance instance
@@ -420,54 +414,43 @@ fn integers() -> Result<()> {
-1 -1
); );
// Returning 100000 should fail for small primitives but succeed for 32-bit. // Returning 100000 should chop off bytes as necessary
let err = instance let ret: u32 = 100000;
assert_eq!(
instance
.get_typed_func::<(), u8, _>(&mut store, "retbig-u8")? .get_typed_func::<(), u8, _>(&mut store, "retbig-u8")?
.call(&mut store, ()) .call(&mut store, ())?,
.unwrap_err(); ret as u8,
assert!(
err.to_string().contains("out of range integral type"),
"{}",
err
); );
let err = instance assert_eq!(
instance
.get_typed_func::<(), i8, _>(&mut store, "retbig-s8")? .get_typed_func::<(), i8, _>(&mut store, "retbig-s8")?
.call(&mut store, ()) .call(&mut store, ())?,
.unwrap_err(); ret as i8,
assert!(
err.to_string().contains("out of range integral type"),
"{}",
err
); );
let err = instance assert_eq!(
instance
.get_typed_func::<(), u16, _>(&mut store, "retbig-u16")? .get_typed_func::<(), u16, _>(&mut store, "retbig-u16")?
.call(&mut store, ()) .call(&mut store, ())?,
.unwrap_err(); ret as u16,
assert!(
err.to_string().contains("out of range integral type"),
"{}",
err
); );
let err = instance assert_eq!(
instance
.get_typed_func::<(), i16, _>(&mut store, "retbig-s16")? .get_typed_func::<(), i16, _>(&mut store, "retbig-s16")?
.call(&mut store, ()) .call(&mut store, ())?,
.unwrap_err(); ret as i16,
assert!(
err.to_string().contains("out of range integral type"),
"{}",
err
); );
assert_eq!( assert_eq!(
instance instance
.get_typed_func::<(), u32, _>(&mut store, "retbig-u32")? .get_typed_func::<(), u32, _>(&mut store, "retbig-u32")?
.call(&mut store, ())?, .call(&mut store, ())?,
100000 ret,
); );
assert_eq!( assert_eq!(
instance instance
.get_typed_func::<(), i32, _>(&mut store, "retbig-s32")? .get_typed_func::<(), i32, _>(&mut store, "retbig-s32")?
.call(&mut store, ())?, .call(&mut store, ())?,
100000 ret as i32,
); );
Ok(()) Ok(())
@@ -622,8 +605,7 @@ fn bools() -> Result<()> {
assert_eq!(bool_to_u32.call(&mut store, (true,))?, 1); assert_eq!(bool_to_u32.call(&mut store, (true,))?, 1);
assert_eq!(u32_to_bool.call(&mut store, (0,))?, false); assert_eq!(u32_to_bool.call(&mut store, (0,))?, false);
assert_eq!(u32_to_bool.call(&mut store, (1,))?, true); assert_eq!(u32_to_bool.call(&mut store, (1,))?, true);
let err = u32_to_bool.call(&mut store, (2,)).unwrap_err(); assert_eq!(u32_to_bool.call(&mut store, (2,))?, true);
assert!(err.to_string().contains("invalid boolean"), "{}", err);
Ok(()) Ok(())
} }
@@ -1305,7 +1287,9 @@ fn char_bool_memory() -> Result<()> {
let ret = func.call(&mut store, (1, '🍰' as u32))?; let ret = func.call(&mut store, (1, '🍰' as u32))?;
assert_eq!(ret, (true, '🍰')); assert_eq!(ret, (true, '🍰'));
assert!(func.call(&mut store, (2, 'a' as u32)).is_err()); let ret = func.call(&mut store, (2, 'a' as u32))?;
assert_eq!(ret, (true, 'a'));
assert!(func.call(&mut store, (0, 0xd800)).is_err()); assert!(func.call(&mut store, (0, 0xd800)).is_err());
Ok(()) Ok(())