Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more tests exercising the component model #606

Merged
merged 1 commit into from May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 0 additions & 25 deletions coverage.sh

This file was deleted.

25 changes: 0 additions & 25 deletions crates/wasmparser/src/binary_reader.rs
Expand Up @@ -924,31 +924,6 @@ impl<'a> BinaryReader<'a> {
Ok(b)
}

/// Advances the `BinaryReader` up to two bytes to parse a variable
/// length integer as a `u8`.
///
/// # Errors
///
/// If `BinaryReader` has less than one or two bytes remaining, or the
/// variable integer is larger than eight bits.
pub fn read_var_u8(&mut self) -> Result<u8> {
// Optimization for single byte i32.
let byte = self.read_u8()?;
if (byte & 0x80) == 0 {
return Ok(byte);
}

let next = self.read_u8()? as u32;
let result: u32 = (next << 7) | (byte & 0x7F) as u32;
if result >= 0x100 {
return Err(BinaryReaderError::new(
"invalid var_u8: integer representation too long",
self.original_position() - 1,
));
}
Ok(result as u8)
}

/// Advances the `BinaryReader` up to four bytes to parse a variable
/// length integer as a `u32`.
///
Expand Down
4 changes: 1 addition & 3 deletions crates/wasmparser/src/validator/component.rs
Expand Up @@ -183,9 +183,7 @@ impl ComponentState {
// export signature
let (params, results) = ty.lower(types, false);

if core_ty.params.as_ref() != params.as_slice()
|| core_ty.returns.as_ref() != results.as_slice()
{
if core_ty.params.as_ref() != params.as_slice() {
return Err(BinaryReaderError::new(
format!("lowered parameter types `{:?}` do not match parameter types `{:?}` of core function {func_index}", params.as_slice(), core_ty.params),
offset,
Expand Down
9 changes: 9 additions & 0 deletions crates/wast/src/component/resolve.rs
Expand Up @@ -222,6 +222,15 @@ fn resolve_alias<'a, 'b>(
export: _,
} => resolve_ns(instance, Ns::Instance, resolve_stack),
AliasTarget::Outer { outer, index } => {
// Short-circuit when both indices are already resolved as this
// helps to write tests for invalid modules where wasmparser should
// be the one returning the error.
if let Index::Num(..) = outer {
if let Index::Num(..) = index {
return Ok(());
}
}

// Resolve `outer`, and compute the depth at which to look up
// `index`.
let depth = match outer {
Expand Down
25 changes: 19 additions & 6 deletions crates/wast/src/wast.rs
Expand Up @@ -109,7 +109,8 @@ impl WastDirective<'_> {
match self {
WastDirective::Wat(QuoteWat::Wat(Wat::Module(m))) => m.span,
WastDirective::Wat(QuoteWat::Wat(Wat::Component(c))) => c.span,
WastDirective::Wat(QuoteWat::Quote(span, _)) => *span,
WastDirective::Wat(QuoteWat::QuoteModule(span, _)) => *span,
WastDirective::Wat(QuoteWat::QuoteComponent(span, _)) => *span,
WastDirective::AssertMalformed { span, .. }
| WastDirective::Register { span, .. }
| WastDirective::AssertTrap { span, .. }
Expand Down Expand Up @@ -271,16 +272,18 @@ impl<'a> Parse<'a> for WastInvoke<'a> {
#[derive(Debug)]
pub enum QuoteWat<'a> {
Wat(Wat<'a>),
Quote(Span, Vec<(Span, &'a [u8])>),
QuoteModule(Span, Vec<(Span, &'a [u8])>),
QuoteComponent(Span, Vec<(Span, &'a [u8])>),
}

impl QuoteWat<'_> {
/// Encodes this module to bytes, either by encoding the module directly or
/// parsing the contents and then encoding it.
pub fn encode(&mut self) -> Result<Vec<u8>, Error> {
let source = match self {
let (source, prefix) = match self {
QuoteWat::Wat(m) => return m.encode(),
QuoteWat::Quote(_, source) => source,
QuoteWat::QuoteModule(_, source) => (source, None),
QuoteWat::QuoteComponent(_, source) => (source, Some("(component")),
};
let mut ret = String::new();
for (span, src) in source {
Expand All @@ -292,6 +295,10 @@ impl QuoteWat<'_> {
}
ret.push_str(" ");
}
if let Some(prefix) = prefix {
ret.insert_str(0, prefix);
ret.push_str(")");
}
let buf = ParseBuffer::new(&ret)?;
let mut wat = parser::parse::<Wat<'_>>(&buf)?;
wat.encode()
Expand All @@ -301,15 +308,21 @@ impl QuoteWat<'_> {
impl<'a> Parse<'a> for QuoteWat<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek2::<kw::quote>() {
parser.parse::<kw::module>()?;
let ctor = if parser.peek::<kw::component>() {
parser.parse::<kw::component>()?;
QuoteWat::QuoteComponent
} else {
parser.parse::<kw::module>()?;
QuoteWat::QuoteModule
};
let span = parser.parse::<kw::quote>()?.0;
let mut src = Vec::new();
while !parser.is_empty() {
let span = parser.cur_span();
let string = parser.parse()?;
src.push((span, string));
}
Ok(QuoteWat::Quote(span, src))
Ok(ctor(span, src))
} else {
Ok(QuoteWat::Wat(parse_wat(parser)?))
}
Expand Down
161 changes: 161 additions & 0 deletions tests/local/component-model/adapt.wast
Expand Up @@ -55,3 +55,164 @@
(canon.lift (func (param string)) string=latin1+utf16 (into $libc)
(func $my_instance "log-compact-utf16")))
)

(assert_invalid
(component
(import "" (func $f))
(func (canon.lower string=utf8 string=utf16 (func $f)))
)
"canonical option `utf8` conflicts with option `utf16`")

(assert_invalid
(component
(import "" (func $f))
(func (canon.lower string=utf8 string=latin1+utf16 (func $f)))
)
"canonical option `utf8` conflicts with option `compact-utf16`")

(assert_invalid
(component
(import "" (func $f))
(func (canon.lower string=utf16 string=latin1+utf16 (func $f)))
)
"canonical option `utf16` conflicts with option `compact-utf16`")

(assert_invalid
(component
(import "" (func $f))
(func (canon.lower (into 0) (func $f)))
)
"instance index out of bounds")

(assert_invalid
(component
(import "" (func $f))
(import "i" (instance $i))
(func (canon.lower (into $i) (func $f)))
)
"not a module instance")

(assert_invalid
(component
(import "" (func $f))
(module $m)
(instance $i (instantiate (module $m)))
(func (canon.lower (into $i) (into $i) (func $f)))
)
"`into` is specified more than once")

(assert_invalid
(component
(module $m
(func (export "") (param i32 i32))
)
(instance $i (instantiate (module $m)))
(func (canon.lift (func (param (list u8))) (func $i "")))
)
"canonical option `into` is required")

(assert_invalid
(component
(module $m
(func (export "") (param i32 i32))
)
(instance $i (instantiate (module $m)))
(func (canon.lift (func (param (list u8))) (into $i) (func $i "")))
)
"does not export a memory")

(assert_invalid
(component
(module $m
(func (export "") (param i32 i32))
(memory (export "memory") 0)
)
(instance $i (instantiate (module $m)))
(func (canon.lift (func (param (list u8))) (into $i) (func $i "")))
)
"does not export a function named `canonical_abi_realloc`")

(assert_invalid
(component
(module $m
(func (export "") (param i32 i32))
(memory (export "memory") 0)
(func (export "canonical_abi_realloc"))
)
(instance $i (instantiate (module $m)))
(func (canon.lift (func (param (list u8))) (into $i) (func $i "")))
)
"wrong signature")

(assert_invalid
(component
(module $m
(func (export "") (param i32 i32))
(memory (export "memory") 0)
(func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32)
unreachable)
)
(instance $i (instantiate (module $m)))
(func (canon.lift (func (param (list u8))) (into $i) (func $i "")))
)
"does not export a function named `canonical_abi_free`")

(assert_invalid
(component
(module $m
(func (export "") (param i32 i32))
(memory (export "memory") 0)
(func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32)
unreachable)
(func (export "canonical_abi_free"))
)
(instance $i (instantiate (module $m)))
(func (canon.lift (func (param (list u8))) (into $i) (func $i "")))
)
"wrong signature")

(assert_invalid
(component
(module $m
(func (export ""))
)
(instance $i (instantiate (module $m)))
(func (canon.lower (func $i "")))
)
"not a component function")

(assert_invalid
(component
(module $m (func (export "foo") (param i32)))
(instance $i (instantiate (module $m)))
(func (export "foo")
(canon.lift (func) (func $i "foo")))
)
"lowered parameter types `[]` do not match parameter types `[I32]`")

(assert_invalid
(component
(module $m (func (export "foo") (result i32)))
(instance $i (instantiate (module $m)))
(func (export "foo")
(canon.lift (func) (func $i "foo")))
)
"lowered result types `[]` do not match result types `[I32]`")

(assert_invalid
(component
(type $f string)
(module $m (func (export "foo")))
(instance $i (instantiate (module $m)))
(func (export "foo")
(canon.lift (type $f) (func $i "foo")))
)
"not a function type")

(assert_invalid
(component
(import "" (func $f))
(func (export "foo")
(canon.lift (func) (func $f)))
)
"not a core WebAssembly function")
16 changes: 16 additions & 0 deletions tests/local/component-model/alias.wast
Expand Up @@ -266,3 +266,19 @@
(alias outer $C $m (component $target))
(export "v" (component $target))
)

(assert_invalid
(component (alias outer 100 0 (module)))
"invalid outer alias count of 100")

(assert_invalid
(component (alias outer 0 0 (module)))
"index out of bounds")

(assert_invalid
(component (alias outer 100 0 (component)))
"invalid outer alias count of 100")

(assert_invalid
(component (alias outer 0 0 (component)))
"index out of bounds")
42 changes: 42 additions & 0 deletions tests/local/component-model/export.wast
Expand Up @@ -4,3 +4,45 @@
(component
(export "" (instance))
)

(assert_invalid
(component (export "" (instance 0)))
"index out of bounds")

(assert_invalid
(component (export "" (component 0)))
"index out of bounds")

(assert_invalid
(component (export "" (module 0)))
"index out of bounds")

(assert_invalid
(component (export "" (func 0)))
"index out of bounds")

(assert_invalid
(component (export "" (value 0)))
"index out of bounds")

(component
(import "1" (instance $i))
(import "2" (module $m))
(import "3" (component $c))
(import "4" (value $v string))
(import "5" (func $f))

(export "1" (instance $i))
(export "2" (module $m))
(export "3" (component $c))
(export "4" (value $v))
(export "5" (func $f))
)

(assert_invalid
(component
(import "" (value $v string))
(export "1" (value $v))
(export "2" (value $v))
)
"cannot be used more than once")