mueval 0.8.2 → 0.9
raw patch · 6 files changed
+60/−16 lines, 6 filesdep +simple-reflect
Dependencies added: simple-reflect
Files
- Mueval/ArgsParse.hs +11/−1
- Mueval/Context.hs +10/−2
- Mueval/Interpreter.hs +18/−3
- Mueval/Parallel.hs +2/−3
- mueval.cabal +6/−6
- tests.sh +13/−1
Mueval/ArgsParse.hs view
@@ -5,7 +5,7 @@ import qualified Codec.Binary.UTF8.String as Codec (decodeString) -import Mueval.Context (defaultModules)+import Mueval.Context (defaultModules, defaultPackages) -- | See the results of --help for information on what each option means. data Options = Options@@ -19,6 +19,8 @@ , namedExtensions :: [String] , noImports :: Bool , rLimits :: Bool+ , packageTrust :: Bool+ , trustedPackages :: [String] , help :: Bool } deriving Show @@ -33,6 +35,8 @@ , namedExtensions = [] , noImports = False , rLimits = False+ , packageTrust = False+ , trustedPackages = defaultPackages , help = False } options :: [OptDescr (Options -> Options)]@@ -68,6 +72,12 @@ Option "r" ["resource-limits"] (NoArg (\opts -> opts { rLimits = True})) "Enable resource limits (using POSIX rlimits). Mueval does not by default since rlimits are broken on many systems.",+ Option "S" ["package-trust"]+ (NoArg (\opts -> opts {packageTrust = True, namedExtensions = "Safe" : namedExtensions opts}))+ "Enable Safe-Haskell package trust system",+ Option "s" ["trust"]+ (ReqArg (\e opts -> opts {trustedPackages = e : trustedPackages opts}) "PACKAGE")+ "Specify a package to be trusted by Safe Haskell (ignored unless -S also present)", Option "h" ["help"] (NoArg (\opts -> opts { help = True})) "Prints out usage info."
Mueval/Context.hs view
@@ -1,6 +1,7 @@ module Mueval.Context ( cleanModules, defaultModules,+ defaultPackages, qualifiedModules, ) where @@ -23,7 +24,7 @@ defaultModules = ["Prelude", "ShowQ", "ShowFun",- "SimpleReflect",+ "Debug.SimpleReflect", "Data.Function", "Control.Applicative", "Control.Arrow",@@ -78,6 +79,13 @@ "Text.PrettyPrint.HughesPJ", "Text.Printf"] +defaultPackages :: [String]+defaultPackages = [ "array"+ , "base"+ , "bytestring"+ , "containers"+ ]+ {- | Borrowed from Lambdabot, this is the whitelist of modules which should be safe to import functions from, but which we don't want to import by default.@@ -97,7 +105,7 @@ ("Data.ByteString.Lazy", Just "BSL"), ("Data.ByteString.Lazy.Char8", Just "BSLC"), ("Data.Foldable", Just "Data.Foldable"),- ("Data.Generics", Just "Data.Generics"),+-- ("Data.Generics", Just "Data.Generics"), ("Data.IntMap", Just "IM"), ("Data.IntSet", Just "IS"), ("Data.Map", Just "M"),
Mueval/Interpreter.hs view
@@ -18,12 +18,19 @@ installedModulesInScope, languageExtensions, typeOf, setTopLevelModules, runInterpreter, glasgowExtensions, OptionVal(..), Interpreter,- InterpreterError(..),GhcError(..))+ InterpreterError(..),GhcError(..),+ Extension(UnknownExtension))+import Language.Haskell.Interpreter.Unsafe (unsafeSetGhcOption) import Mueval.ArgsParse (Options(..)) import qualified Mueval.Resources as MR (limitResources) import qualified Mueval.Context as MC (qualifiedModules) +readExt :: String -> Extension+readExt s = case reads s of+ [(e,[])] -> e+ _ -> UnknownExtension s+ {- | The actual calling of Hint functionality. The heart of this just calls 'eval', but we do so much more - we disable Haskell extensions, hide all packages, make sure one cannot call unimported@@ -33,9 +40,17 @@ interpreter Options { extensions = exts, namedExtensions = nexts, rLimits = rlimits, loadFile = load, expression = expr,+ packageTrust = trust,+ trustedPackages = trustPkgs, modules = m } = do- let lexts = (guard exts >> glasgowExtensions) ++ map read nexts- unless (null lexts) $ set [languageExtensions := lexts]+ let lexts = (guard exts >> glasgowExtensions) ++ map readExt nexts+ -- Explicitly adding ImplicitPrelude because of + -- http://darcsden.com/jcpetruzza/hint/issue/1+ unless (null lexts) $ set [languageExtensions := (UnknownExtension "ImplicitPrelude" : lexts)]+ when trust $ do+ unsafeSetGhcOption "-fpackage-trust"+ flip mapM_ (trustPkgs >>= words) $ \pkg ->+ unsafeSetGhcOption ("-trust " ++ pkg) reset -- Make sure nothing is available set [installedModulesInScope := False]
Mueval/Parallel.hs view
@@ -1,9 +1,8 @@ module Mueval.Parallel where -import Prelude hiding (catch) import Control.Concurrent (forkIO, killThread, myThreadId, threadDelay, throwTo, ThreadId) import System.Posix.Signals (sigXCPU, installHandler, Handler(CatchOnce))-import Control.Exception.Extensible (ErrorCall(..),SomeException,catch)+import Control.Exception.Extensible as E (ErrorCall(..),SomeException,catch) import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar, MVar) import System.IO (hSetBuffering, stdout, BufferMode(NoBuffering)) @@ -43,7 +42,7 @@ -- Our modules and expression are set up. Let's do stuff. forkIO $ (interpreterSession (checkImport opts) >> putMVar mvar "Done.")- `catch` \e -> throwTo mainId (e::SomeException)+ `E.catch` \e -> throwTo mainId (e::SomeException) -- bounce exceptions to the main thread, -- so they are reliably printed out where checkImport x = if noImports x then x{modules=Nothing} else x
mueval.cabal view
@@ -1,5 +1,5 @@ name: mueval-version: 0.8.2+version: 0.9 license: BSD3 license-file: LICENSE@@ -7,13 +7,13 @@ maintainer: Gwern <gwern0@gmail.com> category: Development, Language-synopsis: Safely evaluate Haskell expressions+synopsis: Safely evaluate pure Haskell expressions description: Mueval is a Haskell interpreter. It uses the GHC API to evaluate arbitrary Haskell expressions. Importantly, mueval takes many precautions to defang and avoid \"evil\"- code. It uses resource limits, whitelisted modules,- special Show instances for IO, threads, processes, changes of directory, and so- on to sandbox the Haskell code.+ code. It uses resource limits, whitelisted modules and Safe Haskell,+ special Show instances for IO, threads, processes, and changes of directory+ to sandbox the Haskell code. . It is, in short, intended to be a standalone version of Lambdabot's famous evaluation functionality. For examples and explanations, please see the README file.@@ -32,7 +32,7 @@ exposed-modules: Mueval.Parallel, Mueval.Context, Mueval.Interpreter, Mueval.ArgsParse, Mueval.Resources build-depends: base>=4 && < 5, containers, directory, mtl>2, filepath, unix, process,- hint>=0.3.1, show>=0.3, utf8-string, Cabal, extensible-exceptions+ hint>=0.3.1, show>=0.3, utf8-string, Cabal, extensible-exceptions, simple-reflect ghc-options: -Wall -static -O2 executable mueval-core
tests.sh view
@@ -46,7 +46,7 @@ m 'mysmallcheck (\x -> x < (10000::Int))' -E m 'mysmallcheck (\x -> not x || x)' -E ## Test Unicode. If this fails, characters got mangled somewhere.-m 'let (ñ) = (+) in ñ 5 5'+# m 'let (ñ) = (+) in ñ 5 5' ## Test default imports & have some function fun m 'fix (1:)' m 'fix show'@@ -77,6 +77,7 @@ echo "module TmpModule (foo, bar) where { foo x = x + 1; bar x = x + 2 }" > "TmpModule.hs" m '1+1' --load-file="TmpModule.hs" m 'foo 1' --load-file="TmpModule.hs"+m "foo 1" -S --load-file="TmpModule.hs" m 'bar 1' --load-file="TmpModule.hs" m 'foo $ foo 1' --load-file="TmpModule.hs" rm "TmpModule.hs"@@ -86,6 +87,13 @@ ## Test naming individual syntactic extensions m "let f (id -> x) = x in f 1" -XViewPatterns m "let f :: Int -> State Int (); f (id -> x) = put x in runState (f 1) 1" --module Control.Monad.State -XViewPatterns -XFlexibleContexts+## Test Safe-Haskell-approved code+m "()" -S+m "runReader ask 42" -S --module Control.Monad.Reader+## Setup for later Safe-Haskell tests and ensure that behavior is as+## expected without SH activated+echo 'module TmpModule (unsafePerformIO) where {import System.IO.Unsafe}' > "TmpModule.hs"+m 'unsafePerformIO (readFile "/etc/passwd")' --load-file="TmpModule.hs" ## Test qualified imports m "M.map (+1) $ M.fromList [(1,2), (3,4)]" && echo "\nOK, all the valid expressions worked out well." &&@@ -115,4 +123,8 @@ m 'writeFile "tmp.txt" "foo bar"' || ## Evil array code, should fail (but not with a segfault!) m "array (0::Int, maxBound) [(1000000,'x')]" --module Data.Array ||+## code that should be accepted without Safe Haskell but rejected with+m 'unsafePerformIO (readFile "/etc/passwd")' -S --load-file="TmpModule.hs" || echo "Done, apparently all evil expressions failed to do evil"++rm TmpModule.hs