check if name is valid utf8 string

This commit is contained in:
Ilya Rezvov
2018-04-16 14:35:05 -07:00
parent be47aa7d43
commit 035ffe05da
3 changed files with 42 additions and 45 deletions
+12 -6
View File
@@ -15,6 +15,7 @@ import Control.Applicative ((<$>))
import Control.Monad (when) import Control.Monad (when)
import Numeric.IEEE (infinity, nan) import Numeric.IEEE (infinity, nan)
import Language.Wasm.FloatUtils (makeNaN) import Language.Wasm.FloatUtils (makeNaN)
import Data.Word (Word8)
import qualified Debug.Trace as Debug import qualified Debug.Trace as Debug
@@ -190,7 +191,7 @@ appendFromHead (_pos, _rest, inp, _) _len = do
appendDoubleHexChar :: AlexAction Lexeme appendDoubleHexChar :: AlexAction Lexeme
appendDoubleHexChar (_pos, _rest, inp, _) _len = do appendDoubleHexChar (_pos, _rest, inp, _) _len = do
addCharToLexerStringValue $ Char.chr $ fromIntegral $ readHexFromPrefix 2 $ LBSUtf8.drop 1 inp addCharCodeToLexerStringValue $ fromIntegral $ readHexFromPrefix 2 $ LBSUtf8.drop 1 inp
alexMonadScan alexMonadScan
-- TODO: add a predicate with code ranges check -- TODO: add a predicate with code ranges check
@@ -209,8 +210,8 @@ endStringLiteral :: AlexAction Lexeme
endStringLiteral (pos, _, _inp, _) _len = do endStringLiteral (pos, _, _inp, _) _len = do
alexSetStartCode defaultStartCode alexSetStartCode defaultStartCode
setLexerStringFlag False setLexerStringFlag False
str <- LBSUtf8.fromString . reverse <$> getLexerStringValue str <- LBS.pack . reverse <$> getLexerStringValue
setLexerStringValue "" setLexerStringValue []
return $ Lexeme pos $ TStringLit str return $ Lexeme pos $ TStringLit str
tokenStr :: (LBS.ByteString -> Token) -> AlexAction Lexeme tokenStr :: (LBS.ByteString -> Token) -> AlexAction Lexeme
@@ -236,7 +237,7 @@ data Lexeme = Lexeme { pos :: AlexPosn, tok :: Token } deriving (Show, Eq)
data AlexUserState = AlexUserState { data AlexUserState = AlexUserState {
lexerCommentDepth :: Int, lexerCommentDepth :: Int,
lexerStringValue :: String, lexerStringValue :: [Word8],
lexerIsString :: Bool lexerIsString :: Bool
} }
@@ -262,15 +263,20 @@ setLexerStringFlag :: Bool -> Alex ()
setLexerStringFlag isString = Alex $ \s -> setLexerStringFlag isString = Alex $ \s ->
Right (s{ alex_ust=(alex_ust s){ lexerIsString = isString } }, ()) Right (s{ alex_ust=(alex_ust s){ lexerIsString = isString } }, ())
getLexerStringValue :: Alex String getLexerStringValue :: Alex [Word8]
getLexerStringValue = Alex $ \s@AlexState{alex_ust=ust} -> Right (s, lexerStringValue ust) getLexerStringValue = Alex $ \s@AlexState{alex_ust=ust} -> Right (s, lexerStringValue ust)
setLexerStringValue :: String -> Alex () setLexerStringValue :: [Word8] -> Alex ()
setLexerStringValue ss = Alex $ \s -> setLexerStringValue ss = Alex $ \s ->
Right (s{ alex_ust=(alex_ust s){ lexerStringValue = ss } }, ()) Right (s{ alex_ust=(alex_ust s){ lexerStringValue = ss } }, ())
addCharToLexerStringValue :: Char -> Alex () addCharToLexerStringValue :: Char -> Alex ()
addCharToLexerStringValue c = Alex $ \s -> addCharToLexerStringValue c = Alex $ \s ->
let ust = alex_ust s in
Right (s{ alex_ust = ust{ lexerStringValue = (reverse $ LBS.unpack $ LBSUtf8.fromString [c]) ++ lexerStringValue ust } }, ())
addCharCodeToLexerStringValue :: Word8 -> Alex ()
addCharCodeToLexerStringValue c = Alex $ \s ->
let ust = alex_ust s in let ust = alex_ust s in
Right (s{ alex_ust = ust{ lexerStringValue = c : lexerStringValue ust } }, ()) Right (s{ alex_ust = ust{ lexerStringValue = c : lexerStringValue ust } }, ())
+29 -38
View File
@@ -330,11 +330,18 @@ unrestricted_int { Lexeme _ (TIntLit $$) }
f64 { Lexeme _ (TFloatLit $$) } f64 { Lexeme _ (TFloatLit $$) }
offset { Lexeme _ (TKeyword (asOffset -> Just $$)) } offset { Lexeme _ (TKeyword (asOffset -> Just $$)) }
align { Lexeme _ (TKeyword (asAlign -> Just $$)) } align { Lexeme _ (TKeyword (asAlign -> Just $$)) }
string { Lexeme _ (TStringLit (asString -> Just $$)) } str { Lexeme _ (TStringLit $$) }
EOF { Lexeme _ EOF } EOF { Lexeme _ EOF }
%% %%
string :: { TL.Text }
: str {%
case TLEncoding.decodeUtf8' $1 of
Right t -> Right t
Left err -> Left "invalid utf8 string"
}
name :: { TL.Text } name :: { TL.Text }
: string { $1 } : string { $1 }
@@ -619,40 +626,16 @@ paramsresulttypeuse :: { FuncType }
| 'result' list(valtype) ')' { FuncType [] $2 } | 'result' list(valtype) ')' { FuncType [] $2 }
memarg1 :: { MemArg } memarg1 :: { MemArg }
: opt(offset) opt(align) {% : opt(offset) opt(align) {% parseMemArg 1 $1 $2 }
let offset = fromMaybe 0 $1 in
let align = unpackAlign 1 $2 in
if offset >= 2 ^ 32 || align >= 2 ^ 32
then Left "u32 is out of boundaries"
else return $ MemArg offset align
}
memarg2 :: { MemArg } memarg2 :: { MemArg }
: opt(offset) opt(align) {% : opt(offset) opt(align) {% parseMemArg 2 $1 $2 }
let offset = fromMaybe 0 $1 in
let align = unpackAlign 2 $2 in
if offset >= 2 ^ 32 || align >= 2 ^ 32
then Left "u32 is out of boundaries"
else return $ MemArg offset align
}
memarg4 :: { MemArg } memarg4 :: { MemArg }
: opt(offset) opt(align) {% : opt(offset) opt(align) {% parseMemArg 4 $1 $2 }
let offset = fromMaybe 0 $1 in
let align = unpackAlign 4 $2 in
if offset >= 2 ^ 32 || align >= 2 ^ 32
then Left "u32 is out of boundaries"
else return $ MemArg offset align
}
memarg8 :: { MemArg } memarg8 :: { MemArg }
: opt(offset) opt(align) {% : opt(offset) opt(align) {% parseMemArg 8 $1 $2 }
let offset = fromMaybe 0 $1 in
let align = unpackAlign 8 $2 in
if offset >= 2 ^ 32 || align >= 2 ^ 32
then Left "u32 is out of boundaries"
else return $ MemArg offset align
}
instruction :: { [Instruction] } instruction :: { [Instruction] }
: raw_instr { $1 } : raw_instr { $1 }
@@ -932,8 +915,8 @@ memory_limits_export_import :: { Maybe Ident -> [ModuleField] }
: memory_limits { $1 } : memory_limits { $1 }
| '(' memory_limits_export_import1 { $2 } | '(' memory_limits_export_import1 { $2 }
datastring :: { TL.Text } datastring :: { LBS.ByteString }
: list(string) { TL.concat $1 } : list(str) { LBS.concat $1 }
memory_limits_export_import1 :: { Maybe Ident -> [ModuleField] } memory_limits_export_import1 :: { Maybe Ident -> [ModuleField] }
: 'export' name ')' memory_limits_export_import { : 'export' name ')' memory_limits_export_import {
@@ -944,7 +927,7 @@ memory_limits_export_import1 :: { Maybe Ident -> [ModuleField] }
} }
| 'data' datastring ')' ')' { | 'data' datastring ')' ')' {
\ident -> \ident ->
let m = fromIntegral $ TL.length $2 in let m = fromIntegral $ LBS.length $2 in
[ [
MFMem $ Memory ident $ Limit m $ Just m, MFMem $ Memory ident $ Limit m $ Just m,
MFData $ DataSegment (fromMaybe (Index 0) $ Named `fmap` ident) [PlainInstr $ I32Const 0] $2 MFData $ DataSegment (fromMaybe (Index 0) $ Named `fmap` ident) [PlainInstr $ I32Const 0] $2
@@ -1058,7 +1041,7 @@ command1 :: { Command }
| meta1 { Meta $1 } | meta1 { Meta $1 }
module1 :: { ModuleDef } module1 :: { ModuleDef }
: 'module' opt(ident) 'binary' list(string) ')' { BinaryModDef $2 (LBSChar8.pack $ TL.unpack $ TL.concat $4) } : 'module' opt(ident) 'binary' datastring ')' { BinaryModDef $2 $4 }
| 'module' opt(ident) 'quote' list(string) ')' { TextModDef $2 (TL.concat $4) } | 'module' opt(ident) 'quote' list(string) ')' { TextModDef $2 (TL.concat $4) }
| 'module' opt(ident) list(modulefield) ')' { RawModDef $2 (desugarize $ concat $3) } | 'module' opt(ident) list(modulefield) ')' { RawModDef $2 (desugarize $ concat $3) }
| modulefield1 list(modulefield) { RawModDef Nothing (desugarize $ $1 ++ concat $2) } | modulefield1 list(modulefield) { RawModDef Nothing (desugarize $ $1 ++ concat $2) }
@@ -1145,8 +1128,13 @@ asAlign str = do
num <- TL.stripPrefix "align=" $ TLEncoding.decodeUtf8 str num <- TL.stripPrefix "align=" $ TLEncoding.decodeUtf8 str
fromIntegral . fst <$> eitherToMaybe (TLRead.decimal num) fromIntegral . fst <$> eitherToMaybe (TLRead.decimal num)
unpackAlign :: Natural -> (Maybe Natural) -> Natural parseMemArg :: Natural -> Maybe Natural -> Maybe Natural -> Either String MemArg
unpackAlign def = fromIntegral . round . logBase 2 . fromIntegral . fromMaybe def parseMemArg defAlign optOffset optAlign =
let offset = fromMaybe 0 optOffset in
let align = fromIntegral $ round $ logBase 2 $ fromIntegral $ fromMaybe defAlign optAlign in
if offset >= 2 ^ 32 || align >= 2 ^ 32
then Left "u32 is out of boundaries"
else return $ MemArg offset align
-- TODO: check name conditions. -- TODO: check name conditions.
-- Presuming the source text is itself encoded correctly, -- Presuming the source text is itself encoded correctly,
@@ -1155,7 +1143,10 @@ asName :: LBS.ByteString -> Maybe TL.Text
asName = Just . TLEncoding.decodeUtf8 asName = Just . TLEncoding.decodeUtf8
asString :: LBS.ByteString -> Maybe TL.Text asString :: LBS.ByteString -> Maybe TL.Text
asString = Just . TLEncoding.decodeUtf8 asString bs =
case TLEncoding.decodeUtf8' bs of
Right t -> Just t
Left err -> Nothing
eitherToMaybe :: Either left right -> Maybe right eitherToMaybe :: Either left right -> Maybe right
eitherToMaybe = either (const Nothing) Just eitherToMaybe = either (const Nothing) Just
@@ -1363,7 +1354,7 @@ data ElemSegment = ElemSegment {
data DataSegment = DataSegment { data DataSegment = DataSegment {
memIndex :: MemoryIndex, memIndex :: MemoryIndex,
offset :: [Instruction], offset :: [Instruction],
datastring :: TL.Text datastring :: LBS.ByteString
} }
deriving (Show, Eq, Generic, NFData) deriving (Show, Eq, Generic, NFData)
@@ -1806,7 +1797,7 @@ desugarize fields =
let ctx = FunCtx mod [] [] [] in let ctx = FunCtx mod [] [] [] in
let offsetInstrs = map (synInstrToStruct ctx) offset in let offsetInstrs = map (synInstrToStruct ctx) offset in
let idx = fromJust $ getMemIndex mod memIndex in let idx = fromJust $ getMemIndex mod memIndex in
S.DataSegment idx offsetInstrs $ LBSChar8.pack $ TL.unpack datastring S.DataSegment idx offsetInstrs datastring
extractDataSegment :: [DataSegment] -> ModuleField -> [DataSegment] extractDataSegment :: [DataSegment] -> ModuleField -> [DataSegment]
extractDataSegment datas (MFData dataSegment) = dataSegment : datas extractDataSegment datas (MFData dataSegment) = dataSegment : datas
+1 -1
View File
@@ -34,7 +34,7 @@ compile file = do
main :: IO () main :: IO ()
main = do main = do
files <- Directory.listDirectory "tests/samples" files <- Directory.listDirectory "tests/samples"
-- let files = ["data.wast"] -- let files = ["utf8-invalid-encoding.wast"]
scriptTestCases <- (`mapM` files) $ \file -> do scriptTestCases <- (`mapM` files) $ \file -> do
content <- LBS.readFile $ "tests/samples/" ++ file content <- LBS.readFile $ "tests/samples/" ++ file
let Right script = Lexer.scanner content >>= Parser.parseScript let Right script = Lexer.scanner content >>= Parser.parseScript