forbid special nan values for non-script contexts

This commit is contained in:
Ilya Rezvov
2023-08-21 21:11:39 -06:00
parent d321bf6a9c
commit d0403ad554
2 changed files with 60 additions and 42 deletions
+4
View File
@@ -5,6 +5,8 @@ module Language.Wasm.Lexer (
Lexeme(..), Lexeme(..),
Token(..), Token(..),
AlexPosn(..), AlexPosn(..),
FloatRep(..),
NaN(..),
scanner, scanner,
asFloat, asFloat,
asDouble, asDouble,
@@ -22,6 +24,8 @@ import Data.List (isPrefixOf)
import Text.Read (readEither) import Text.Read (readEither)
import Data.Bits import Data.Bits
import Numeric (showHex) import Numeric (showHex)
import Control.DeepSeq (NFData)
import GHC.Generics (Generic)
} }
+56 -42
View File
@@ -93,6 +93,8 @@ import Language.Wasm.Lexer (
), ),
Lexeme(..), Lexeme(..),
AlexPosn(..), AlexPosn(..),
FloatRep(..),
NaN(..),
asFloat, asFloat,
asDouble, asDouble,
doubleFromInteger doubleFromInteger
@@ -407,23 +409,23 @@ int64 :: { Integer }
else Left ("Int literal value is out of signed int64 boundaries: " ++ show $1) else Left ("Int literal value is out of signed int64 boundaries: " ++ show $1)
} }
float32 :: { Float } float32 :: { FloatRep }
: int {% : int {%
let maxInt = 340282356779733623858607532500980858880 in let maxInt = 340282356779733623858607532500980858880 in
if $1 <= maxInt && $1 >= -maxInt if $1 <= maxInt && $1 >= -maxInt
then return $ fromIntegral $1 then return $ BinRep $ fromIntegral $1
else Left "constant out of range" else Left "constant out of range"
} }
| f64 {% asFloat $1 } | f64 { $1 }
float64 :: { Double } float64 :: { FloatRep }
: int {% : int {%
let maxInt = round (maxFinite :: Double) in let maxInt = round (maxFinite :: Double) in
if $1 <= maxInt && $1 >= -maxInt if $1 <= maxInt && $1 >= -maxInt
then doubleFromInteger $1 then fmap BinRep $ doubleFromInteger $1
else Left "constant out of range" else Left "constant out of range"
} }
| f64 {% asDouble $1 } | f64 { $1 }
plaininstr :: { PlainInstr } plaininstr :: { PlainInstr }
-- control instructions -- control instructions
@@ -1040,11 +1042,15 @@ module1 :: { ModuleDef }
| 'module' opt(ident) list(modulefield) ')' {% RawModDef $2 `fmap` (desugarize $ concat $3) } | 'module' opt(ident) list(modulefield) ')' {% RawModDef $2 `fmap` (desugarize $ concat $3) }
action1 :: { Action } action1 :: { Action }
: 'invoke' opt(ident) string list(folded_instr) ')' { Invoke $2 $3 (map (map constInstructionToValue) $4) } : 'invoke' opt(ident) string list(folded_instr) ')' {%
fmap (Invoke $2 $3) $ (mapM (mapM constInstructionToValue) $4)
}
| 'get' opt(ident) string ')' { Get $2 $3 } | 'get' opt(ident) string ')' { Get $2 $3 }
assertion1 :: { (Maybe AlexPosn, Assertion) } assertion1 :: { (Maybe AlexPosn, Assertion) }
: 'assert_return' '(' action1 list(folded_instr) ')' { ($1, AssertReturn $3 (map (map constInstructionToValue) $4)) } : 'assert_return' '(' action1 list(folded_instr) ')' {%
fmap ((\a -> ($1, a)) . AssertReturn $3) $ (mapM (mapM constInstructionToValue) $4)
}
| 'assert_return_canonical_nan' '(' action1 ')' { ($1, AssertReturnCanonicalNaN $3) } | 'assert_return_canonical_nan' '(' action1 ')' { ($1, AssertReturnCanonicalNaN $3) }
| 'assert_return_arithmetic_nan' '(' action1 ')' { ($1, AssertReturnArithmeticNaN $3) } | 'assert_return_arithmetic_nan' '(' action1 ')' { ($1, AssertReturnArithmeticNaN $3) }
| 'assert_trap' '(' assertion_trap string ')' { ($1, AssertTrap $3 $4) } | 'assert_trap' '(' assertion_trap string ')' { ($1, AssertTrap $3 $4) }
@@ -1160,7 +1166,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, Generic, NFData) data FuncType = FuncType { params :: [ParamType], results :: [ValueType] } deriving (Show, Eq)
emptyFuncType :: FuncType emptyFuncType :: FuncType
emptyFuncType = FuncType [] [] emptyFuncType = FuncType [] []
@@ -1168,11 +1174,11 @@ emptyFuncType = FuncType [] []
data ParamType = ParamType { data ParamType = ParamType {
ident :: Maybe Ident, ident :: Maybe Ident,
paramType :: ValueType paramType :: ValueType
} deriving (Show, Eq, Generic, NFData) } deriving (Show, Eq)
newtype Ident = Ident TL.Text deriving (Show, Eq, Generic, NFData) newtype Ident = Ident TL.Text deriving (Show, Eq)
data Index = Named Ident | Index Natural deriving (Show, Eq, Generic, NFData) data Index = Named Ident | Index Natural deriving (Show, Eq)
type LabelIndex = Index type LabelIndex = Index
type FuncIndex = Index type FuncIndex = Index
@@ -1245,8 +1251,8 @@ data PlainInstr =
-- Numeric instructions -- Numeric instructions
| I32Const Integer | I32Const Integer
| I64Const Integer | I64Const Integer
| F32Const Float | F32Const FloatRep
| F64Const Double | F64Const FloatRep
| IUnOp BitSize IUnOp | IUnOp BitSize IUnOp
| IBinOp BitSize IBinOp | IBinOp BitSize IBinOp
| I32Eqz | I32Eqz
@@ -1268,14 +1274,14 @@ data PlainInstr =
| F64PromoteF32 | F64PromoteF32
| IReinterpretF BitSize | IReinterpretF BitSize
| FReinterpretI BitSize | FReinterpretI BitSize
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
data TypeDef = TypeDef (Maybe Ident) FuncType deriving (Show, Eq, Generic, NFData) data TypeDef = TypeDef (Maybe Ident) FuncType deriving (Show, Eq)
data TypeUse = data TypeUse =
IndexedTypeUse TypeIndex (Maybe FuncType) IndexedTypeUse TypeIndex (Maybe FuncType)
| AnonimousTypeUse FuncType | AnonimousTypeUse FuncType
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
emptyTypeUse = AnonimousTypeUse emptyFuncType emptyTypeUse = AnonimousTypeUse emptyFuncType
@@ -1297,26 +1303,26 @@ data Instruction =
trueBranch :: [Instruction], trueBranch :: [Instruction],
falseBranch :: [Instruction] falseBranch :: [Instruction]
} }
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
data Import = Import { data Import = Import {
reExportAs :: [TL.Text], reExportAs :: [TL.Text],
sourceModule :: TL.Text, sourceModule :: TL.Text,
name :: TL.Text, name :: TL.Text,
desc :: ImportDesc desc :: ImportDesc
} deriving (Show, Eq, Generic, NFData) } deriving (Show, Eq)
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, Generic, NFData) deriving (Show, Eq)
data LocalType = LocalType { data LocalType = LocalType {
ident :: Maybe Ident, ident :: Maybe Ident,
localType :: ValueType localType :: ValueType
} deriving (Show, Eq, Generic, NFData) } deriving (Show, Eq)
data Function = Function { data Function = Function {
exportFuncAs :: [TL.Text], exportFuncAs :: [TL.Text],
@@ -1325,7 +1331,7 @@ data Function = Function {
locals :: [LocalType], locals :: [LocalType],
body :: [Instruction] body :: [Instruction]
} }
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
emptyFunction :: Function emptyFunction :: Function
emptyFunction = emptyFunction =
@@ -1343,32 +1349,32 @@ data Global = Global {
globalType :: GlobalType, globalType :: GlobalType,
initializer :: [Instruction] initializer :: [Instruction]
} }
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
data Memory = Memory [TL.Text] (Maybe Ident) Limit deriving (Show, Eq, Generic, NFData) data Memory = Memory [TL.Text] (Maybe Ident) Limit deriving (Show, Eq)
data Table = Table [TL.Text] (Maybe Ident) TableType deriving (Show, Eq, Generic, NFData) data Table = Table [TL.Text] (Maybe Ident) TableType deriving (Show, Eq)
data ExportDesc = data ExportDesc =
ExportFunc FuncIndex ExportFunc FuncIndex
| ExportTable TableIndex | ExportTable TableIndex
| ExportMemory MemoryIndex | ExportMemory MemoryIndex
| ExportGlobal GlobalIndex | ExportGlobal GlobalIndex
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
data Export = Export { data Export = Export {
name :: TL.Text, name :: TL.Text,
desc :: ExportDesc desc :: ExportDesc
} }
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
data StartFunction = StartFunction FuncIndex deriving (Show, Eq, Generic, NFData) data StartFunction = StartFunction FuncIndex deriving (Show, Eq)
data ElemMode data ElemMode
= Passive = Passive
| Active TableIndex [Instruction] | Active TableIndex [Instruction]
| Declarative | Declarative
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
data ElemSegment = ElemSegment { data ElemSegment = ElemSegment {
ident :: Maybe Ident, ident :: Maybe Ident,
@@ -1376,14 +1382,14 @@ data ElemSegment = ElemSegment {
mode :: ElemMode, mode :: ElemMode,
elements :: [[Instruction]] elements :: [[Instruction]]
} }
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
data DataSegment = DataSegment { data DataSegment = DataSegment {
memIndex :: MemoryIndex, memIndex :: MemoryIndex,
offset :: [Instruction], offset :: [Instruction],
datastring :: LBS.ByteString datastring :: LBS.ByteString
} }
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq)
data ModuleField = data ModuleField =
MFType TypeDef MFType TypeDef
@@ -1396,7 +1402,7 @@ data ModuleField =
| MFStart StartFunction | MFStart StartFunction
| MFElem ElemSegment | MFElem ElemSegment
| MFData DataSegment | MFData DataSegment
deriving(Show, Eq, Generic, NFData) deriving(Show, Eq)
happyError (Lexeme _ EOF : []) = Left $ "Error occuried during parsing phase at the end of file" happyError (Lexeme _ EOF : []) = Left $ "Error occuried during parsing phase at the end of file"
happyError (Lexeme Nothing tok : tokens) = Left $ "Error occuried during parsing phase at the end of file" happyError (Lexeme Nothing tok : tokens) = Left $ "Error occuried during parsing phase at the end of file"
@@ -1469,14 +1475,14 @@ data FunCtx = FunCtx {
ctxParams :: [ParamType] ctxParams :: [ParamType]
} deriving (Eq, Show) } deriving (Eq, Show)
constInstructionToValue :: Instruction -> S.Instruction Natural constInstructionToValue :: Instruction -> Either String (S.Instruction Natural)
constInstructionToValue (PlainInstr (I32Const v)) = S.I32Const $ integerToWord32 v constInstructionToValue (PlainInstr (I32Const v)) = return $ S.I32Const $ integerToWord32 v
constInstructionToValue (PlainInstr (F32Const v)) = S.F32Const v constInstructionToValue (PlainInstr (F32Const v)) = S.F32Const <$> asFloat v
constInstructionToValue (PlainInstr (I64Const v)) = S.I64Const $ integerToWord64 v constInstructionToValue (PlainInstr (I64Const v)) = return $ S.I64Const $ integerToWord64 v
constInstructionToValue (PlainInstr (F64Const v)) = S.F64Const v constInstructionToValue (PlainInstr (F64Const v)) = S.F64Const <$> asDouble v
constInstructionToValue (PlainInstr (RefNull et)) = S.RefNull et constInstructionToValue (PlainInstr (RefNull et)) = return $ S.RefNull et
constInstructionToValue (PlainInstr (RefExtern n)) = S.RefExtern n constInstructionToValue (PlainInstr (RefExtern n)) = return $ S.RefExtern n
constInstructionToValue _ = error "Only const instructions supported as arguments for actions" constInstructionToValue _ = Left "Only const instructions supported as arguments for actions"
funcIndexToExpr :: [FuncIndex] -> [[Instruction]] funcIndexToExpr :: [FuncIndex] -> [[Instruction]]
funcIndexToExpr = map $ (:[]) . PlainInstr . RefFunc funcIndexToExpr = map $ (:[]) . PlainInstr . RefFunc
@@ -1759,8 +1765,16 @@ desugarize fields = do
Nothing -> Left "unknown elem" Nothing -> Left "unknown elem"
synInstrToStruct _ (PlainInstr (I32Const val)) = return $ S.I32Const $ integerToWord32 val synInstrToStruct _ (PlainInstr (I32Const val)) = return $ S.I32Const $ integerToWord32 val
synInstrToStruct _ (PlainInstr (I64Const val)) = return $ S.I64Const $ integerToWord64 val synInstrToStruct _ (PlainInstr (I64Const val)) = return $ S.I64Const $ integerToWord64 val
synInstrToStruct _ (PlainInstr (F32Const val)) = return $ S.F32Const val synInstrToStruct _ (PlainInstr (F32Const (NanRep Arithmetic))) =
synInstrToStruct _ (PlainInstr (F64Const val)) = return $ S.F64Const val Left "arithmetic nan constant allowed only in script"
synInstrToStruct _ (PlainInstr (F32Const (NanRep Canonical))) =
Left "canonical nan constant allowed only in script"
synInstrToStruct _ (PlainInstr (F32Const rep)) = S.F32Const <$> asFloat rep
synInstrToStruct _ (PlainInstr (F64Const (NanRep Arithmetic))) =
Left "arithmetic nan constant allowed only in script"
synInstrToStruct _ (PlainInstr (F64Const (NanRep Canonical))) =
Left "canonical nan constant allowed only in script"
synInstrToStruct _ (PlainInstr (F64Const rep)) = S.F64Const <$> asDouble rep
synInstrToStruct _ (PlainInstr (IUnOp sz op)) = return $ S.IUnOp sz op synInstrToStruct _ (PlainInstr (IUnOp sz op)) = return $ S.IUnOp sz op
synInstrToStruct _ (PlainInstr (IBinOp sz op)) = return $ S.IBinOp sz op synInstrToStruct _ (PlainInstr (IBinOp sz op)) = return $ S.IBinOp sz op
synInstrToStruct _ (PlainInstr I32Eqz) = return $ S.I32Eqz synInstrToStruct _ (PlainInstr I32Eqz) = return $ S.I32Eqz