diff --git a/src/Language/Wasm/Binary.hs b/src/Language/Wasm/Binary.hs index 56f7527..4a6f0fa 100644 --- a/src/Language/Wasm/Binary.hs +++ b/src/Language/Wasm/Binary.hs @@ -130,7 +130,10 @@ getSection sectionType parser def = do where parseSection op | op == 0 = skipCustomSection >> getSection sectionType parser def - | op == fromEnum sectionType = getWord8 >> (getULEB128 32 :: Get Natural) >> parser + | op == fromEnum sectionType = do + getWord8 + len <- getULEB128 32 + isolate len parser | op > fromEnum DataSection = fail "invalid section id" | op > fromEnum sectionType = return def | otherwise = @@ -522,6 +525,15 @@ instance Serialize (Instruction Natural) where put (IUnOp BS64 IExtend16S) = putWord8 0xC3 put (IUnOp BS64 IExtend32S) = putWord8 0xC4 + put (ITruncSatFS BS32 BS32) = putWord8 0xFC >> putULEB128 (0x00 :: Word32) + put (ITruncSatFU BS32 BS32) = putWord8 0xFC >> putULEB128 (0x01 :: Word32) + put (ITruncSatFS BS32 BS64) = putWord8 0xFC >> putULEB128 (0x02 :: Word32) + put (ITruncSatFU BS32 BS64) = putWord8 0xFC >> putULEB128 (0x03 :: Word32) + put (ITruncSatFS BS64 BS32) = putWord8 0xFC >> putULEB128 (0x04 :: Word32) + put (ITruncSatFU BS64 BS32) = putWord8 0xFC >> putULEB128 (0x05 :: Word32) + put (ITruncSatFS BS64 BS64) = putWord8 0xFC >> putULEB128 (0x06 :: Word32) + put (ITruncSatFU BS64 BS64) = putWord8 0xFC >> putULEB128 (0x07 :: Word32) + get = do op <- getWord8 case op of @@ -711,6 +723,18 @@ instance Serialize (Instruction Natural) where 0xC2 -> return $ IUnOp BS64 IExtend8S 0xC3 -> return $ IUnOp BS64 IExtend16S 0xC4 -> return $ IUnOp BS64 IExtend32S + 0xFC -> do -- misc + ext <- getULEB128 32 + case (ext :: Word32) of + 0x00 -> return $ ITruncSatFS BS32 BS32 + 0x01 -> return $ ITruncSatFU BS32 BS32 + 0x02 -> return $ ITruncSatFS BS32 BS64 + 0x03 -> return $ ITruncSatFU BS32 BS64 + 0x04 -> return $ ITruncSatFS BS64 BS32 + 0x05 -> return $ ITruncSatFU BS64 BS32 + 0x06 -> return $ ITruncSatFS BS64 BS64 + 0x07 -> return $ ITruncSatFU BS64 BS64 + _ -> fail "Unknown byte value after misc instruction byte" _ -> fail "Unknown byte value in place of instruction opcode" putExpression :: Expression -> Put @@ -792,7 +816,10 @@ instance Serialize Function where putByteString bs get = do _size <- getULEB128 32 :: Get Natural - locals <- concat . map (\(LocalTypeRange n val) -> replicate (fromIntegral n) val) <$> getVec + localRanges <- getVec + let localLen = sum $ map (\(LocalTypeRange n _) -> n) localRanges + if localLen < 2^32 then return () else fail "too many locals" + let locals = concat $ map (\(LocalTypeRange n val) -> replicate (fromIntegral n) val) localRanges body <- getExpression return $ Function 0 locals body diff --git a/src/Language/Wasm/Interpreter.hs b/src/Language/Wasm/Interpreter.hs index fb40ce7..99dfd43 100644 --- a/src/Language/Wasm/Interpreter.hs +++ b/src/Language/Wasm/Interpreter.hs @@ -1079,21 +1079,81 @@ eval budget store FunctionInstance { funcType, moduleInstance, code = Function { then return Trap else return $ Done ctx { stack = VI64 (truncate v) : rest } step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncFS BS32 BS32) = - if isNaN v || isInfinite v || v >= 2^31 || v < -2^31 + if isNaN v || isInfinite v || v >= 2^31 || v < -2^31 - 1 then return Trap else return $ Done ctx { stack = VI32 (asWord32 $ truncate v) : rest } step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncFS BS32 BS64) = - if isNaN v || isInfinite v || v >= 2^31 || v < -2^31 + if isNaN v || isInfinite v || v >= 2^31 || v <= -2^31 - 1 then return Trap else return $ Done ctx { stack = VI32 (asWord32 $ truncate v) : rest } step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncFS BS64 BS32) = - if isNaN v || isInfinite v || v >= 2^63 || v < -2^63 + if isNaN v || isInfinite v || v >= 2^63 || v < -2^63 - 1 then return Trap else return $ Done ctx { stack = VI64 (asWord64 $ truncate v) : rest } step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncFS BS64 BS64) = - if isNaN v || isInfinite v || v >= 2^63 || v < -2^63 + if isNaN v || isInfinite v || v >= 2^63 || v < -2^63 - 1 then return Trap else return $ Done ctx { stack = VI64 (asWord64 $ truncate v) : rest } + + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFS BS32 BS32) | isNaN v = + return $ Done ctx { stack = VI32 0 : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFS BS32 BS64) | isNaN v = + return $ Done ctx { stack = VI32 0 : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFS BS64 BS32) | isNaN v = + return $ Done ctx { stack = VI64 0 : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFS BS64 BS64) | isNaN v = + return $ Done ctx { stack = VI64 0 : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFU BS32 BS32) | v <= -1 || isNaN v = + return $ Done ctx { stack = VI32 0 : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFU BS32 BS64) | v <= -1 || isNaN v = + return $ Done ctx { stack = VI32 0 : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFU BS64 BS32) | v <= -1 || isNaN v = + return $ Done ctx { stack = VI64 0 : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFU BS64 BS64) | v <= -1 || isNaN v = + return $ Done ctx { stack = VI64 0 : rest } + + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFS BS32 BS32) | v >= 2^31 = + return $ Done ctx { stack = VI32 0x7fffffff : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFS BS32 BS64) | v >= 2^31 = + return $ Done ctx { stack = VI32 0x7fffffff : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFS BS64 BS32) | v >= 2^63 = + return $ Done ctx { stack = VI64 0x7fffffffffffffff : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFS BS64 BS64) | v >= 2^63 = + return $ Done ctx { stack = VI64 0x7fffffffffffffff : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFU BS32 BS32) | v >= 2^32 = + return $ Done ctx { stack = VI32 0xffffffff : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFU BS32 BS64) | v >= 2^32 = + return $ Done ctx { stack = VI32 0xffffffff : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFU BS64 BS32) | v >= 2^64 = + return $ Done ctx { stack = VI64 0xffffffffffffffff : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFU BS64 BS64) | v >= 2^64 = + return $ Done ctx { stack = VI64 0xffffffffffffffff : rest } + + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFS BS32 BS32) | v <= -2^31 - 1 = + return $ Done ctx { stack = VI32 0x80000000 : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFS BS32 BS64) | v <= -2^31 - 1 = + return $ Done ctx { stack = VI32 0x80000000 : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFS BS64 BS32) | v <= -2^63 - 1 = + return $ Done ctx { stack = VI64 0x8000000000000000 : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFS BS64 BS64) | v <= -2^63 - 1 = + return $ Done ctx { stack = VI64 0x8000000000000000 : rest } + + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFU BS32 BS32) = + return $ Done ctx { stack = VI32 (truncate v) : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFU BS32 BS64) = + return $ Done ctx { stack = VI32 (truncate v) : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFU BS64 BS32) = + return $ Done ctx { stack = VI64 (truncate v) : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFU BS64 BS64) = + return $ Done ctx { stack = VI64 (truncate v) : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFS BS32 BS32) = + return $ Done ctx { stack = VI32 (asWord32 $ truncate v) : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFS BS32 BS64) = + return $ Done ctx { stack = VI32 (asWord32 $ truncate v) : rest } + step ctx@EvalCtx{ stack = (VF32 v:rest) } (ITruncSatFS BS64 BS32) = + return $ Done ctx { stack = VI64 (asWord64 $ truncate v) : rest } + step ctx@EvalCtx{ stack = (VF64 v:rest) } (ITruncSatFS BS64 BS64) = + return $ Done ctx { stack = VI64 (asWord64 $ truncate v) : rest } step ctx@EvalCtx{ stack = (VI32 v:rest) } I64ExtendUI32 = return $ Done ctx { stack = VI64 (fromIntegral v) : rest } step ctx@EvalCtx{ stack = (VI32 v:rest) } I64ExtendSI32 = diff --git a/tests/Test.hs b/tests/Test.hs index a71f6cc..26cd597 100644 --- a/tests/Test.hs +++ b/tests/Test.hs @@ -17,7 +17,7 @@ import qualified Data.List as List main :: IO () main = do files <- filter (List.isSuffixOf ".wast") <$> Directory.listDirectory "tests/spec" - -- let files = ["select.wast"] + -- let files = ["conversions.wast"] scriptTestCases <- (`mapM` files) $ \file -> do test <- LBS.readFile ("tests/spec/" ++ file) return $ testCase file $ do