Disallow direct call of host functions (#723)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
@@ -37,20 +37,12 @@ func main() {
|
||||
r := wazero.NewRuntime()
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
// Add a module that uses offset parameters for multiple results.
|
||||
|
||||
// ... defined in WebAssembly.
|
||||
// Add a module that uses offset parameters for multiple results defined in WebAssembly.
|
||||
wasm, err := resultOffsetWasmFunctions(ctx, r)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// ... defined in Go.
|
||||
host, err := resultOffsetHostFunctions(ctx, r)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// wazero enables WebAssembly 1.0 by default. Opt-in to other features:
|
||||
runtimeWithMultiValue := wazero.NewRuntimeWithConfig(
|
||||
wazero.NewRuntimeConfig().WithFeatureMultiValue(true),
|
||||
@@ -66,13 +58,13 @@ func main() {
|
||||
}
|
||||
|
||||
// ... defined in Go.
|
||||
hostWithMultiValue, err := multiValueHostFunctions(ctx, runtimeWithMultiValue)
|
||||
multiValueFromImportedHost, err := multiValueFromImportedHostWasmFunctions(ctx, runtimeWithMultiValue)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// Call the function from each module and print the results to the console.
|
||||
for _, mod := range []api.Module{wasm, host, wasmWithMultiValue, hostWithMultiValue} {
|
||||
for _, mod := range []api.Module{wasm, wasmWithMultiValue, multiValueFromImportedHost} {
|
||||
getAge := mod.ExportedFunction("call_get_age")
|
||||
results, err := getAge.Call(ctx)
|
||||
if err != nil {
|
||||
@@ -83,36 +75,6 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// resultOffsetHostFunctions defines host functions that illustrate multiple
|
||||
// results using a technique compatible with any WebAssembly 1.0 runtime.
|
||||
//
|
||||
// To return a value in WASM written to a result parameter, you have to define
|
||||
// memory and pass a location to write the result. At the end of your function,
|
||||
// you load that location.
|
||||
func resultOffsetHostFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) {
|
||||
return r.NewModuleBuilder("result-offset/host").
|
||||
// To use result parameters, we need scratch memory. Allocate the least
|
||||
// possible: 1 page (64KB).
|
||||
ExportMemoryWithMax("mem", 1, 1).
|
||||
// get_age returns a result, while a second result is written to memory.
|
||||
ExportFunction("get_age", func(ctx context.Context, m api.Module, resultOffsetAge uint32) (errno uint32) {
|
||||
if m.Memory().WriteUint64Le(ctx, resultOffsetAge, 37) {
|
||||
return 0
|
||||
}
|
||||
return 1 // overflow
|
||||
}).
|
||||
// Now, define a function that shows the Wasm mechanics returning
|
||||
// something written to a result parameter. The caller provides a
|
||||
// memory offset to the callee, so that it knows where to write the
|
||||
// second result.
|
||||
ExportFunction("call_get_age", func(ctx context.Context, m api.Module) (age uint64) {
|
||||
resultOffsetAge := uint32(8) // arbitrary memory offset (in bytes)
|
||||
_, _ = m.ExportedFunction("get_age").Call(ctx, uint64(resultOffsetAge))
|
||||
age, _ = m.Memory().ReadUint64Le(ctx, resultOffsetAge)
|
||||
return
|
||||
}).Instantiate(ctx, r)
|
||||
}
|
||||
|
||||
// resultOffsetWasm was generated by the following:
|
||||
//
|
||||
// cd testdata; wat2wasm --debug-names result_offset.wat
|
||||
@@ -126,23 +88,6 @@ func resultOffsetWasmFunctions(ctx context.Context, r wazero.Runtime) (api.Modul
|
||||
return r.InstantiateModuleFromBinary(ctx, resultOffsetWasm)
|
||||
}
|
||||
|
||||
// multiValueHostFunctions defines Wasm functions that illustrate multiple
|
||||
// results using the "multiple-results" feature.
|
||||
func multiValueHostFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) {
|
||||
return r.NewModuleBuilder("multi-value/host").
|
||||
// Define a function that returns two results
|
||||
ExportFunction("get_age", func() (age uint64, errno uint32) {
|
||||
age = 37
|
||||
errno = 0
|
||||
return
|
||||
}).
|
||||
// Now, define a function that returns only the first result.
|
||||
ExportFunction("call_get_age", func(ctx context.Context, m api.Module) (age uint64) {
|
||||
results, _ := m.ExportedFunction("get_age").Call(ctx)
|
||||
return results[0]
|
||||
}).Instantiate(ctx, r)
|
||||
}
|
||||
|
||||
// multiValueWasm was generated by the following:
|
||||
//
|
||||
// cd testdata; wat2wasm --debug-names multi_value.wat
|
||||
@@ -155,3 +100,21 @@ var multiValueWasm []byte
|
||||
func multiValueWasmFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) {
|
||||
return r.InstantiateModuleFromBinary(ctx, multiValueWasm)
|
||||
}
|
||||
|
||||
// multiValueWasm was generated by the following:
|
||||
//
|
||||
// cd testdata; wat2wasm --debug-names multi_value_imported.wat
|
||||
//
|
||||
//go:embed testdata/multi_value_imported.wasm
|
||||
var multiValueFromImportedHostWasm []byte
|
||||
|
||||
func multiValueFromImportedHostWasmFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) {
|
||||
r.NewModuleBuilder("multi-value/host").
|
||||
// Define a function that returns two results
|
||||
ExportFunction("get_age", func() (age uint64, errno uint32) {
|
||||
age = 37
|
||||
errno = 0
|
||||
return
|
||||
}).Instantiate(ctx, r)
|
||||
return r.InstantiateModuleFromBinary(ctx, multiValueFromImportedHostWasm)
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@ import (
|
||||
func Test_main(t *testing.T) {
|
||||
stdout, _ := maintester.TestMain(t, main, "multiple-results")
|
||||
require.Equal(t, `result-offset/wasm: age=37
|
||||
result-offset/host: age=37
|
||||
multi-value/wasm: age=37
|
||||
multi-value/host: age=37
|
||||
multi-value/imported_host: age=37
|
||||
`, stdout)
|
||||
}
|
||||
|
||||
BIN
examples/multiple-results/testdata/multi_value_imported.wasm
vendored
Normal file
BIN
examples/multiple-results/testdata/multi_value_imported.wasm
vendored
Normal file
Binary file not shown.
12
examples/multiple-results/testdata/multi_value_imported.wat
vendored
Normal file
12
examples/multiple-results/testdata/multi_value_imported.wat
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
;; multiValueWasmFunctions defines Wasm functions that illustrate multiple
|
||||
;; results using the "multiple-results" feature.
|
||||
(module $multi-value/imported_host
|
||||
;; Imports the `get_age` function from `multi-value/host` defined in the host.
|
||||
(func $get_age (import "multi-value/host" "get_age") (result (;age;) i64 (;errno;) i32))
|
||||
|
||||
;; Now, define a function that returns only the first result.
|
||||
(func (export "call_get_age") (result i64)
|
||||
call $get_age ;; stack = [37, errno] result of get_age
|
||||
drop ;; stack = [37]
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user