implemented assert_malformed assertion and added NFData instances for all parsing types

This commit is contained in:
Ilya Rezvov
2018-04-15 16:16:11 -07:00
parent 73124a3eff
commit 09f4b15d2c
6 changed files with 85 additions and 56 deletions
+6
View File
@@ -20,3 +20,9 @@
* [ ] Compile Core Tests to Tasty test cases and pass all tests * [ ] Compile Core Tests to Tasty test cases and pass all tests
* [ ] Command line tool for calling interpreter/compiler/validator * [ ] Command line tool for calling interpreter/compiler/validator
* [ ] Codegen interface for type enforced generating valid WASM code * [ ] Codegen interface for type enforced generating valid WASM code
## Development
Clond sources to directory and use `stack` for running tests:
```
stack && stack test
```
+13 -8
View File
@@ -96,8 +96,10 @@ skipCustomSection :: Get ()
skipCustomSection = do skipCustomSection = do
byteGuard 0x00 byteGuard 0x00
size <- getULEB128 size <- getULEB128
getByteString size content <- getByteString size
return () case runGet getName content of
Right _name -> return ()
Left _ -> fail "invalid UTF-8 encoding"
getSection :: SectionType -> Get a -> a -> Get a getSection :: SectionType -> Get a -> a -> Get a
getSection sectionType parser def = do getSection sectionType parser def = do
@@ -111,6 +113,7 @@ getSection sectionType parser def = do
parseSection op parseSection op
| op == 0 = skipCustomSection >> getSection sectionType parser def | op == 0 = skipCustomSection >> getSection sectionType parser def
| op == fromEnum sectionType = getWord8 >> (getULEB128 :: Get Natural) >> parser | op == fromEnum sectionType = getWord8 >> (getULEB128 :: Get Natural) >> parser
| op > fromEnum DataSection = fail "invalid section id"
| op > fromEnum sectionType = return def | op > fromEnum sectionType = return def
| otherwise = | otherwise =
fail $ "Incorrect order of sections. Expected " ++ show sectionType fail $ "Incorrect order of sections. Expected " ++ show sectionType
@@ -126,7 +129,9 @@ getName :: Get TL.Text
getName = do getName = do
len <- getULEB128 len <- getULEB128
bytes <- getLazyByteString len bytes <- getLazyByteString len
return $ TLEncoding.decodeUtf8 bytes case TLEncoding.decodeUtf8' bytes of
Right name -> return name
Left _ -> fail "invalid UTF-8 encoding"
putResultType :: ResultType -> Put putResultType :: ResultType -> Put
putResultType [] = putWord8 0x40 putResultType [] = putWord8 0x40
@@ -230,7 +235,7 @@ instance Serialize GlobalType where
case op of case op of
0x00 -> return $ Const valType 0x00 -> return $ Const valType
0x01 -> return $ Mut valType 0x01 -> return $ Mut valType
_ -> fail "Unexpected byte in place of Global type opcode" _ -> fail "invalid mutability"
instance Serialize ImportDesc where instance Serialize ImportDesc where
put (ImportFunc typeIdx) = putWord8 0x00 >> putULEB128 typeIdx put (ImportFunc typeIdx) = putWord8 0x00 >> putULEB128 typeIdx
@@ -770,10 +775,10 @@ instance Serialize Module where
putSection DataSection $ putVec $ datas mod putSection DataSection $ putVec $ datas mod
get = do get = do
-- magic magic <- getWord32be
mapM_ byteGuard [0x00, 0x61, 0x73, 0x6D] if magic == 0x0061736D then return () else fail "magic header not detected"
-- version version <- getWord32be
mapM_ byteGuard [0x01, 0x00, 0x00, 0x00] if version == 0x01000000 then return () else fail "unknown binary version"
types <- getSection TypeSection getVec [] types <- getSection TypeSection getVec []
imports <- getSection ImportSection getVec [] imports <- getSection ImportSection getVec []
funcTypes <- getSection FunctionSection getVec [] funcTypes <- getSection FunctionSection getVec []
+25 -21
View File
@@ -3,6 +3,8 @@
{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
module Language.Wasm.Parser ( module Language.Wasm.Parser (
parseModule, parseModule,
@@ -73,6 +75,8 @@ import Data.Word (Word32, Word64)
import Data.Bits ((.|.)) import Data.Bits ((.|.))
import Numeric.IEEE (infinity, nan) import Numeric.IEEE (infinity, nan)
import Language.Wasm.FloatUtils (doubleToFloat) import Language.Wasm.FloatUtils (doubleToFloat)
import Control.DeepSeq (NFData)
import GHC.Generics (Generic)
import Language.Wasm.Lexer ( import Language.Wasm.Lexer (
Token ( Token (
@@ -1143,7 +1147,7 @@ integerToWord64 i
| i < 0 && i >= -(2 ^ 63) = 0xFFFFFFFFFFFFFFFF - (fromIntegral (abs i)) + 1 | i < 0 && i >= -(2 ^ 63) = 0xFFFFFFFFFFFFFFFF - (fromIntegral (abs i)) + 1
| otherwise = error "I64 is out of bounds." | otherwise = error "I64 is out of bounds."
data FuncType = FuncType { params :: [ParamType], results :: [ValueType] } deriving (Show, Eq) data FuncType = FuncType { params :: [ParamType], results :: [ValueType] } deriving (Show, Eq, Generic, NFData)
emptyFuncType :: FuncType emptyFuncType :: FuncType
emptyFuncType = FuncType [] [] emptyFuncType = FuncType [] []
@@ -1151,11 +1155,11 @@ emptyFuncType = FuncType [] []
data ParamType = ParamType { data ParamType = ParamType {
ident :: Maybe Ident, ident :: Maybe Ident,
paramType :: ValueType paramType :: ValueType
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
newtype Ident = Ident TL.Text deriving (Show, Eq) newtype Ident = Ident TL.Text deriving (Show, Eq, Generic, NFData)
data Index = Named Ident | Index Natural deriving (Show, Eq) data Index = Named Ident | Index Natural deriving (Show, Eq, Generic, NFData)
type LabelIndex = Index type LabelIndex = Index
type FuncIndex = Index type FuncIndex = Index
@@ -1234,14 +1238,14 @@ data PlainInstr =
| F64PromoteF32 | F64PromoteF32
| IReinterpretF BitSize | IReinterpretF BitSize
| FReinterpretI BitSize | FReinterpretI BitSize
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data TypeDef = TypeDef (Maybe Ident) FuncType deriving (Show, Eq) data TypeDef = TypeDef (Maybe Ident) FuncType deriving (Show, Eq, Generic, NFData)
data TypeUse = data TypeUse =
IndexedTypeUse TypeIndex (Maybe FuncType) IndexedTypeUse TypeIndex (Maybe FuncType)
| AnonimousTypeUse FuncType | AnonimousTypeUse FuncType
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data Instruction = data Instruction =
PlainInstr PlainInstr PlainInstr PlainInstr
@@ -1261,25 +1265,25 @@ data Instruction =
trueBranch :: [Instruction], trueBranch :: [Instruction],
falseBranch :: [Instruction] falseBranch :: [Instruction]
} }
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data Import = Import { data Import = Import {
sourceModule :: TL.Text, sourceModule :: TL.Text,
name :: TL.Text, name :: TL.Text,
desc :: ImportDesc desc :: ImportDesc
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
data ImportDesc = data ImportDesc =
ImportFunc (Maybe Ident) TypeUse ImportFunc (Maybe Ident) TypeUse
| ImportTable (Maybe Ident) TableType | ImportTable (Maybe Ident) TableType
| ImportMemory (Maybe Ident) Limit | ImportMemory (Maybe Ident) Limit
| ImportGlobal (Maybe Ident) GlobalType | ImportGlobal (Maybe Ident) GlobalType
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data LocalType = LocalType { data LocalType = LocalType {
ident :: Maybe Ident, ident :: Maybe Ident,
localType :: ValueType localType :: ValueType
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
data Function = Function { data Function = Function {
ident :: Maybe Ident, ident :: Maybe Ident,
@@ -1287,7 +1291,7 @@ data Function = Function {
locals :: [LocalType], locals :: [LocalType],
body :: [Instruction] body :: [Instruction]
} }
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
emptyFunction :: Function emptyFunction :: Function
emptyFunction = emptyFunction =
@@ -1303,40 +1307,40 @@ data Global = Global {
globalType :: GlobalType, globalType :: GlobalType,
initializer :: [Instruction] initializer :: [Instruction]
} }
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data Memory = Memory (Maybe Ident) Limit deriving (Show, Eq) data Memory = Memory (Maybe Ident) Limit deriving (Show, Eq, Generic, NFData)
data Table = Table (Maybe Ident) TableType deriving (Show, Eq) data Table = Table (Maybe Ident) TableType deriving (Show, Eq, Generic, NFData)
data ExportDesc = data ExportDesc =
ExportFunc (Maybe FuncIndex) ExportFunc (Maybe FuncIndex)
| ExportTable (Maybe TableIndex) | ExportTable (Maybe TableIndex)
| ExportMemory (Maybe MemoryIndex) | ExportMemory (Maybe MemoryIndex)
| ExportGlobal (Maybe GlobalIndex) | ExportGlobal (Maybe GlobalIndex)
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data Export = Export { data Export = Export {
name :: TL.Text, name :: TL.Text,
desc :: ExportDesc desc :: ExportDesc
} }
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data StartFunction = StartFunction FuncIndex deriving (Show, Eq) data StartFunction = StartFunction FuncIndex deriving (Show, Eq, Generic, NFData)
data ElemSegment = ElemSegment { data ElemSegment = ElemSegment {
tableIndex :: TableIndex, tableIndex :: TableIndex,
offset :: [Instruction], offset :: [Instruction],
funcIndexes :: [FuncIndex] funcIndexes :: [FuncIndex]
} }
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data DataSegment = DataSegment { data DataSegment = DataSegment {
memIndex :: MemoryIndex, memIndex :: MemoryIndex,
offset :: [Instruction], offset :: [Instruction],
datastring :: TL.Text datastring :: TL.Text
} }
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data ModuleField = data ModuleField =
MFType TypeDef MFType TypeDef
@@ -1349,7 +1353,7 @@ data ModuleField =
| MFStart StartFunction | MFStart StartFunction
| MFElem ElemSegment | MFElem ElemSegment
| MFData DataSegment | MFData DataSegment
deriving(Show, Eq) deriving(Show, Eq, Generic, NFData)
happyError (Lexeme _ EOF : []) = error $ "Error occuried during parsing phase at the end of file" happyError (Lexeme _ EOF : []) = error $ "Error occuried during parsing phase at the end of file"
happyError (Lexeme (AlexPn abs line col) tok : tokens) = error $ happyError (Lexeme (AlexPn abs line col) tok : tokens) = error $
+9
View File
@@ -9,6 +9,7 @@ import qualified Data.Vector as Vector
import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TLEncoding import qualified Data.Text.Lazy.Encoding as TLEncoding
import Numeric.IEEE (identicalIEEE) import Numeric.IEEE (identicalIEEE)
import qualified Control.DeepSeq as DeepSeq
import Language.Wasm.Parser ( import Language.Wasm.Parser (
Ident(..), Ident(..),
@@ -197,6 +198,14 @@ runScript onAssertFail script = do
++ ", but actual is " ++ ", but actual is "
++ show (getFailureString reason) ++ show (getFailureString reason)
in onAssertFail msg assert in onAssertFail msg assert
runAssert st assert@(AssertMalformed (TextModDef _ textRep) failureString) =
case DeepSeq.force $ Parser.parseModule <$> Lexer.scanner (TLEncoding.encodeUtf8 textRep) of
Right _ -> onAssertFail ("Module parsing should fail with failure string " ++ show failureString) assert
Left _ -> return ()
runAssert st assert@(AssertMalformed (BinaryModDef ident binaryRep) failureString) =
case Binary.decodeModuleLazy binaryRep of
Right _ -> onAssertFail ("Module decoding should fail with failure string " ++ show failureString) assert
Left _ -> return ()
runAssert _ _ = return () runAssert _ _ = return ()
runCommand :: ScriptState -> Command -> IO ScriptState runCommand :: ScriptState -> Command -> IO ScriptState
+31 -27
View File
@@ -1,4 +1,6 @@
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
module Language.Wasm.Structure ( module Language.Wasm.Structure (
Module(..), Module(..),
@@ -44,10 +46,12 @@ import Numeric.Natural (Natural)
import Data.Word (Word32, Word64) import Data.Word (Word32, Word64)
import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy as TL
import Control.DeepSeq (NFData)
import GHC.Generics (Generic)
data BitSize = BS32 | BS64 deriving (Show, Eq) data BitSize = BS32 | BS64 deriving (Show, Eq, Generic, NFData)
data IUnOp = IClz | ICtz | IPopcnt deriving (Show, Eq) data IUnOp = IClz | ICtz | IPopcnt deriving (Show, Eq, Generic, NFData)
data IBinOp = data IBinOp =
IAdd IAdd
@@ -65,17 +69,17 @@ data IBinOp =
| IShrS | IShrS
| IRotl | IRotl
| IRotr | IRotr
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data IRelOp = IEq | INe | ILtU | ILtS | IGtU | IGtS | ILeU | ILeS | IGeU | IGeS deriving (Show, Eq) data IRelOp = IEq | INe | ILtU | ILtS | IGtU | IGtS | ILeU | ILeS | IGeU | IGeS deriving (Show, Eq, Generic, NFData)
data FUnOp = FAbs | FNeg | FCeil | FFloor | FTrunc | FNearest | FSqrt deriving (Show, Eq) data FUnOp = FAbs | FNeg | FCeil | FFloor | FTrunc | FNearest | FSqrt deriving (Show, Eq, Generic, NFData)
data FBinOp = FAdd | FSub | FMul | FDiv | FMin | FMax | FCopySign deriving (Show, Eq) data FBinOp = FAdd | FSub | FMul | FDiv | FMin | FMax | FCopySign deriving (Show, Eq, Generic, NFData)
data FRelOp = FEq | FNe | FLt | FGt | FLe | FGe deriving (Show, Eq) data FRelOp = FEq | FNe | FLt | FGt | FLe | FGe deriving (Show, Eq, Generic, NFData)
data MemArg = MemArg { offset :: Natural, align :: Natural } deriving (Show, Eq) data MemArg = MemArg { offset :: Natural, align :: Natural } deriving (Show, Eq, Generic, NFData)
type LabelIndex = Natural type LabelIndex = Natural
type FuncIndex = Natural type FuncIndex = Natural
@@ -90,13 +94,13 @@ data ValueType =
| I64 | I64
| F32 | F32
| F64 | F64
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
type ResultType = [ValueType] type ResultType = [ValueType]
type ParamsType = [ValueType] type ParamsType = [ValueType]
type LocalsType = [ValueType] type LocalsType = [ValueType]
data FuncType = FuncType { params :: ParamsType, results :: ResultType } deriving (Show, Eq) data FuncType = FuncType { params :: ParamsType, results :: ResultType } deriving (Show, Eq, Generic, NFData)
data Instruction = data Instruction =
-- Control instructions -- Control instructions
@@ -170,7 +174,7 @@ data Instruction =
| F64PromoteF32 | F64PromoteF32
| IReinterpretF BitSize | IReinterpretF BitSize
| FReinterpretI BitSize | FReinterpretI BitSize
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
type Expression = [Instruction] type Expression = [Instruction]
@@ -178,63 +182,63 @@ data Function = Function {
funcType :: TypeIndex, funcType :: TypeIndex,
localTypes :: LocalsType, localTypes :: LocalsType,
body :: Expression body :: Expression
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
data Limit = Limit Natural (Maybe Natural) deriving (Show, Eq) data Limit = Limit Natural (Maybe Natural) deriving (Show, Eq, Generic, NFData)
data ElemType = AnyFunc deriving (Show, Eq) data ElemType = AnyFunc deriving (Show, Eq, Generic, NFData)
data TableType = TableType Limit ElemType deriving (Show, Eq) data TableType = TableType Limit ElemType deriving (Show, Eq, Generic, NFData)
data Table = Table TableType deriving (Show, Eq) data Table = Table TableType deriving (Show, Eq, Generic, NFData)
data Memory = Memory Limit deriving (Show, Eq) data Memory = Memory Limit deriving (Show, Eq, Generic, NFData)
data GlobalType = Const ValueType | Mut ValueType deriving (Show, Eq) data GlobalType = Const ValueType | Mut ValueType deriving (Show, Eq, Generic, NFData)
data Global = Global { data Global = Global {
globalType :: GlobalType, globalType :: GlobalType,
initializer :: Expression initializer :: Expression
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
data ElemSegment = ElemSegment { data ElemSegment = ElemSegment {
tableIndex :: TableIndex, tableIndex :: TableIndex,
offset :: [Instruction], offset :: [Instruction],
funcIndexes :: [FuncIndex] funcIndexes :: [FuncIndex]
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
data DataSegment = DataSegment { data DataSegment = DataSegment {
memIndex :: MemoryIndex, memIndex :: MemoryIndex,
offset :: Expression, offset :: Expression,
chunk :: LBS.ByteString chunk :: LBS.ByteString
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
data StartFunction = StartFunction FuncIndex deriving (Show, Eq) data StartFunction = StartFunction FuncIndex deriving (Show, Eq, Generic, NFData)
data ExportDesc = data ExportDesc =
ExportFunc FuncIndex ExportFunc FuncIndex
| ExportTable TableIndex | ExportTable TableIndex
| ExportMemory MemoryIndex | ExportMemory MemoryIndex
| ExportGlobal GlobalIndex | ExportGlobal GlobalIndex
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data Export = Export { data Export = Export {
name :: TL.Text, name :: TL.Text,
desc :: ExportDesc desc :: ExportDesc
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
data ImportDesc = data ImportDesc =
ImportFunc TypeIndex ImportFunc TypeIndex
| ImportTable TableType | ImportTable TableType
| ImportMemory Limit | ImportMemory Limit
| ImportGlobal GlobalType | ImportGlobal GlobalType
deriving (Show, Eq) deriving (Show, Eq, Generic, NFData)
data Import = Import { data Import = Import {
sourceModule :: TL.Text, sourceModule :: TL.Text,
name :: TL.Text, name :: TL.Text,
desc :: ImportDesc desc :: ImportDesc
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
isFuncImport :: Import -> Bool isFuncImport :: Import -> Bool
isFuncImport (Import _ _ (ImportFunc _)) = True isFuncImport (Import _ _ (ImportFunc _)) = True
@@ -263,7 +267,7 @@ data Module = Module {
start :: Maybe StartFunction, start :: Maybe StartFunction,
imports :: [Import], imports :: [Import],
exports :: [Export] exports :: [Export]
} deriving (Show, Eq) } deriving (Show, Eq, Generic, NFData)
emptyModule :: Module emptyModule :: Module
emptyModule = Module { emptyModule = Module {
+1
View File
@@ -32,6 +32,7 @@ library
, cereal >= 0.5 , cereal >= 0.5
, vector >= 0.12 , vector >= 0.12
, ieee754 >= 0.8 , ieee754 >= 0.8
, deepseq >= 1.4
build-tools: build-tools:
alex >=3.1.3 alex >=3.1.3
, happy >=1.9.4 , happy >=1.9.4