fix nan with payload parsing and safely handle out of range type indecies

This commit is contained in:
Ilya Rezvov
2021-04-07 22:38:34 -07:00
parent fa1d9a7bd1
commit 53bdf096a4
2 changed files with 36 additions and 7 deletions
+29 -6
View File
@@ -14,9 +14,9 @@ import qualified Data.ByteString.Lazy as LBS
import qualified Data.Char as Char import qualified Data.Char as Char
import qualified Data.ByteString.Lazy.UTF8 as LBSUtf8 import qualified Data.ByteString.Lazy.UTF8 as LBSUtf8
import Control.Monad (when) import Control.Monad (when)
import Numeric.IEEE (infinity, nan) import Numeric.IEEE (infinity, nan, nanWithPayload)
import Language.Wasm.FloatUtils (makeNaN, doubleToFloat) import Language.Wasm.FloatUtils (makeNaN, doubleToFloat)
import Data.Word (Word8) import Data.Word (Word8, Word64)
import Data.List (isPrefixOf) import Data.List (isPrefixOf)
import Text.Read (readEither) import Text.Read (readEither)
@@ -62,8 +62,8 @@ tokens :-
<0> "nan" { constToken $ TFloatLit $ BinRep (abs nan) } <0> "nan" { constToken $ TFloatLit $ BinRep (abs nan) }
<0> "+nan" { constToken $ TFloatLit $ BinRep (abs nan) } <0> "+nan" { constToken $ TFloatLit $ BinRep (abs nan) }
<0> "-nan" { constToken $ TFloatLit $ BinRep nan } <0> "-nan" { constToken $ TFloatLit $ BinRep nan }
<0> "nan:canonical" { constToken $ TFloatLit $ BinRep nan } <0> "nan:canonical" { constToken $ TFloatLit $ NanRep Canonical }
<0> "nan:arithmetic" { constToken $ TFloatLit $ BinRep nan } <0> "nan:arithmetic" { constToken $ TFloatLit $ NanRep Arithmetic }
<0> $sign? @nanhex { parseNanSigned } <0> $sign? @nanhex { parseNanSigned }
<0> "inf" { constToken $ TFloatLit $ BinRep inf } <0> "inf" { constToken $ TFloatLit $ BinRep inf }
<0> "+inf" { constToken $ TFloatLit $ BinRep inf } <0> "+inf" { constToken $ TFloatLit $ BinRep inf }
@@ -131,9 +131,13 @@ parseHexalSignedInt = token $ \(pos, _, s, _) len ->
parseNanSigned :: AlexAction Lexeme parseNanSigned :: AlexAction Lexeme
parseNanSigned = token $ \(pos, _, s, _) len -> parseNanSigned = token $ \(pos, _, s, _) len ->
let (sign, slen) = parseSign s in let (sign, slen) = case LBSUtf8.decode s of
Just ('-', _) -> (False, 1)
Just ('+', _) -> (True, 1)
otherwise -> (True, 0)
in
let num = readHexFromPrefix (len - 6 - slen) $ LBSUtf8.drop (6 + slen) s in let num = readHexFromPrefix (len - 6 - slen) $ LBSUtf8.drop (6 + slen) s in
Lexeme (Just pos) $ TFloatLit $ BinRep $ sign $ makeNaN $ fromIntegral num Lexeme (Just pos) $ TFloatLit $ NanRep $ NanHex sign $ fromIntegral num
parseDecimalSignedInt :: AlexAction Lexeme parseDecimalSignedInt :: AlexAction Lexeme
parseDecimalSignedInt = token $ \(pos, _, s, _) len -> parseDecimalSignedInt = token $ \(pos, _, s, _) len ->
@@ -218,11 +222,23 @@ asFloat :: FloatRep -> Either String Float
asFloat (BinRep d) = Right $ doubleToFloat d asFloat (BinRep d) = Right $ doubleToFloat d
asFloat (HexRep s) = doubleToFloat <$> readHexFloat 128 "ffffff" s asFloat (HexRep s) = doubleToFloat <$> readHexFloat 128 "ffffff" s
asFloat (DecRep s) = readDecFloat s asFloat (DecRep s) = readDecFloat s
asFloat (NanRep Canonical) = Right nan
asFloat (NanRep Arithmetic) = Right nan
asFloat (NanRep (NanHex isPos payload)) =
if payload >= 1 && payload < 2 ^ 23
then return $ doubleToFloat $ (if isPos then id else negate) $ makeNaN payload
else Left "constant out of range"
asDouble :: FloatRep -> Either String Double asDouble :: FloatRep -> Either String Double
asDouble (BinRep d) = Right d asDouble (BinRep d) = Right d
asDouble (HexRep s) = readHexFloat 1024 "fffffffffffff8" s asDouble (HexRep s) = readHexFloat 1024 "fffffffffffff8" s
asDouble (DecRep s) = readDecDouble s asDouble (DecRep s) = readDecDouble s
asDouble (NanRep Canonical) = Right nan
asDouble (NanRep Arithmetic) = Right nan
asDouble (NanRep (NanHex isPos payload)) =
if payload >= 1 && payload < 2 ^ 52
then return $ (if isPos then id else negate) $ makeNaN payload
else Left "constant out of range"
startBlockComment :: AlexAction Lexeme startBlockComment :: AlexAction Lexeme
startBlockComment _inp _len = do startBlockComment _inp _len = do
@@ -300,6 +316,13 @@ data FloatRep
= BinRep Double = BinRep Double
| DecRep String | DecRep String
| HexRep String | HexRep String
| NanRep NaN
deriving (Show, Eq)
data NaN
= Canonical
| Arithmetic
| NanHex Bool Word64
deriving (Show, Eq) deriving (Show, Eq)
data Token = TKeyword LBS.ByteString data Token = TKeyword LBS.ByteString
+7 -1
View File
@@ -1461,6 +1461,11 @@ desugarize fields = do
else (TypeDef Nothing funcType) : defs else (TypeDef Nothing funcType) : defs
matchTypeUse defs _ = defs matchTypeUse defs _ = defs
nth :: Natural -> [a] -> Maybe a
nth 0 (x : xs) = Just x
nth n (_ : xs) = nth (n - 1) xs
nth _ _ = Nothing
getTypeIndex :: [TypeDef] -> TypeUse -> Maybe Natural getTypeIndex :: [TypeDef] -> TypeUse -> Maybe Natural
getTypeIndex defs (AnonimousTypeUse funcType) = getTypeIndex defs (AnonimousTypeUse funcType) =
fromIntegral <$> findIndex (matchTypeFunc funcType) defs fromIntegral <$> findIndex (matchTypeFunc funcType) defs
@@ -1471,7 +1476,8 @@ desugarize fields = do
getTypeIndex defs (IndexedTypeUse (Named ident) Nothing) = getTypeIndex defs (IndexedTypeUse (Named ident) Nothing) =
fromIntegral <$> findIndex (\(TypeDef i _) -> i == Just ident) defs fromIntegral <$> findIndex (\(TypeDef i _) -> i == Just ident) defs
getTypeIndex defs (IndexedTypeUse (Index n) (Just funcType)) = do getTypeIndex defs (IndexedTypeUse (Index n) (Just funcType)) = do
guard $ matchTypeFunc funcType $ defs !! fromIntegral n def <- nth n defs
guard $ matchTypeFunc funcType def
return n return n
getTypeIndex defs (IndexedTypeUse (Index n) Nothing) = return n getTypeIndex defs (IndexedTypeUse (Index n) Nothing) = return n