SPY / haskell-wasm

Haskell WebAssembly Toolkit
Other
151 stars 24 forks source link

Eval doesn't check number of input arguments #12

Open agustinmista opened 3 years ago

agustinmista commented 3 years ago

Hi!

I found a issue in the implementation of eval/invoke in Language.Wasm.Interpreter.

Right now, invocation arguments are only type-matched pairwise using zipWith checkValType. This silently drops any non-matched argument when the two lists have different length, providing confusing results because the indices of the locals get shifted to the left.

For instance, if I do:

ghci> m = Module {types = [FuncType {params = [I32,I32], results = [I32]}], functions = [Function {funcType = 0, localTypes = [I32], body = [GetLocal 1]}], tables = [], mems = [], globals = [], elems = [], datas = [], start = Nothing, imports = [], exports = [Export {name = "foo", desc = ExportFunc 0}]}

ghci> Right vm = validate m

ghci> Right (mi, s) <- instantiate emptyStore mempty vm

Then, invoking "foo" with a single argument doesn't fail, but instead it returns the value of the first zero-initialized local:

ghci> invokeExport s mi "foo" [VI32 10, VI32 20]
Just [VI32 20]

ghci> invokeExport s mi "foo" [VI32 10]
Just [VI32 0]

Running this in the reference implementation works as expected, raising a runtime error:

$ ./wasm -i foo.wasm -e '(invoke "foo" (i32.const 10) (i32.const 20))'
20 : i32

$ ./wasm -i foo.wasm -e '(invoke "foo" (i32.const 10))'
foo.wasm:0x30-0x37: runtime crash: wrong number or types of arguments

The easiest way of solving this could be to add a small check at the top of eval:

eval :: Natural -> Store -> FunctionInstance -> [Value] -> IO (Maybe [Value])
eval 0 _ _ _ = return Nothing
eval _ _ FunctionInstance { funcType } args | length args /= length (params funcType) = return Nothing
eval budget store FunctionInstance { funcType, moduleInstance, code = Function { localTypes, body} } args = ...

I fixed the code in my fork just like this, but I would be happy to open a PR with a different solution if you like.

/Agustín

SPY commented 3 years ago

Hi

Your PR is highly welcome.

Instead of silently return Nothing in eval function I would throw an explicit error like error "Arguments mismatch" in invoke implementation. Besides arguments count I would check types of arguments too.