Safe Haskell | None |
---|---|
Language | Haskell2010 |
The embedded Ruby interpreter must run on its own thread. The functions in this module should enforce this property. For lower level access, please look at Foreign.Ruby.Bindings and Foreign.Ruby.Helpers.
withRubyInterpreter $ \i -> do dsqsddqs
Synopsis
- data RubyInterpreter
- startRubyInterpreter :: IO RubyInterpreter
- closeRubyInterpreter :: RubyInterpreter -> IO ()
- withRubyInterpreter :: (RubyInterpreter -> IO a) -> IO a
- loadFile :: RubyInterpreter -> FilePath -> IO (Either RubyError ())
- embedHaskellValue :: RubyInterpreter -> a -> IO (Either RubyError RValue)
- safeMethodCall :: RubyInterpreter -> String -> String -> [RValue] -> IO (Either RubyError RValue)
- safeFunCall :: RubyInterpreter -> RValue -> String -> [RValue] -> IO (Either RubyError RValue)
- makeSafe :: RubyInterpreter -> IO a -> IO (Either RubyError a)
- data RubyError
- type RValue = Ptr CULong
- type RID = CULong
- fromRuby :: FromRuby a => RubyInterpreter -> RValue -> IO (Either RubyError a)
- toRuby :: ToRuby a => RubyInterpreter -> a -> IO (Either RubyError RValue)
- freezeGC :: RubyInterpreter -> IO a -> IO a
- getSymbol :: String -> IO RValue
- freeHaskellValue :: RValue -> IO ()
- extractHaskellValue :: RValue -> IO a
- type RubyFunction1 = RValue -> IO RValue
- type RubyFunction2 = RValue -> RValue -> IO RValue
- type RubyFunction3 = RValue -> RValue -> RValue -> IO RValue
- type RubyFunction4 = RValue -> RValue -> RValue -> RValue -> IO RValue
- type RubyFunction5 = RValue -> RValue -> RValue -> RValue -> RValue -> IO RValue
- registerGlobalFunction1 :: RubyInterpreter -> String -> RubyFunction1 -> IO (Either RubyError ())
- registerGlobalFunction2 :: RubyInterpreter -> String -> RubyFunction2 -> IO (Either RubyError ())
- registerGlobalFunction3 :: RubyInterpreter -> String -> RubyFunction3 -> IO (Either RubyError ())
- registerGlobalFunction4 :: RubyInterpreter -> String -> RubyFunction4 -> IO (Either RubyError ())
- registerGlobalFunction5 :: RubyInterpreter -> String -> RubyFunction5 -> IO (Either RubyError ())
Initialization / cleanup
data RubyInterpreter Source #
This is actually a newtype around a TQueue
.
startRubyInterpreter :: IO RubyInterpreter Source #
Initializes a Ruby interpreter. This should only be called once. It actually runs an internal server in a dedicated OS thread.
closeRubyInterpreter :: RubyInterpreter -> IO () Source #
This will shut the internal server down.
withRubyInterpreter :: (RubyInterpreter -> IO a) -> IO a Source #
This is basically :
bracket startRubyInterpreter closeRubyInterpreter
Running Ruby actions
embedHaskellValue :: RubyInterpreter -> a -> IO (Either RubyError RValue) Source #
This transforms any Haskell value into a Ruby big integer encoding the
address of the corresponding StablePtr
. This is useful when you want
to pass such values to a Ruby program that will call Haskell functions.
This is probably a bad idea to do this. The use case is for calling Haskell functions from Ruby, using values generated from the Haskell world. If your main program is in Haskell, you should probably wrap a function partially applied with the value you would want to embed.
safeMethodCall :: RubyInterpreter -> String -> String -> [RValue] -> IO (Either RubyError RValue) Source #
A safe version of the corresponding Foreign.Ruby.Helper function.
safeFunCall :: RubyInterpreter -> RValue -> String -> [RValue] -> IO (Either RubyError RValue) Source #
A safe version of the corresponding Foreign.Ruby.Helper function.
makeSafe :: RubyInterpreter -> IO a -> IO (Either RubyError a) Source #
Runs an arbitrary computation in the Ruby interpreter thread. This is useful if you want to embed calls from lower level functions. You still need to be careful about the GC's behavior.
Converting to and from Ruby values
type RValue = Ptr CULong Source #
This is the type of Ruby values. It is defined as a pointer to some unsigned long, just like Ruby does. The actual value is either pointed to, or encoded in the pointer.
fromRuby :: FromRuby a => RubyInterpreter -> RValue -> IO (Either RubyError a) Source #
Converts a Ruby value to some Haskell type..
toRuby :: ToRuby a => RubyInterpreter -> a -> IO (Either RubyError RValue) Source #
Insert a value in the Ruby runtime. You must always use such
a function and the resulting RValue ina freezeGC
call.
freezeGC :: RubyInterpreter -> IO a -> IO a Source #
Runs a computation with the Ruby GC disabled. Once the computation is over, GC will be re-enabled and the startGC
function run.
Callbacks
These functions could be used to call Haskell functions from the Ruby world. While fancier stuff could be achieved by tapping into Foreign.Ruby.Bindings, those methods should be easy to use and should cover most use cases.
The embedHaskellValue
, extractHaskellValue
and
freeHaskellValue
functions are very unsafe, and should be used only in very
controlled environments.
freeHaskellValue :: RValue -> IO () Source #
Frees the Haskell value represented by the corresponding RValue
.
This is probably extremely unsafe to do, and will most certainly lead to
exploitable security bug if you use something modified from Ruby land.
You should always free the RValue
you generated from
embedHaskellValue
.
extractHaskellValue :: RValue -> IO a Source #
This is unsafe as hell, so you'd better be certain this RValue has not been tempered with : GC frozen, bugfree Ruby scripts.
If it has been tempered by an attacker, you are probably looking at a good vector for arbitrary code execution.
type RubyFunction1 = RValue -> IO RValue Source #
All those function types can be used to register functions to the Ruby
runtime. Please note that the first argument is always set (it is
"self"). For this reason, there is no RubyFunction0
type.
registerGlobalFunction1 :: RubyInterpreter -> String -> RubyFunction1 -> IO (Either RubyError ()) Source #
registerGlobalFunction2 :: RubyInterpreter -> String -> RubyFunction2 -> IO (Either RubyError ()) Source #
registerGlobalFunction3 :: RubyInterpreter -> String -> RubyFunction3 -> IO (Either RubyError ()) Source #
registerGlobalFunction4 :: RubyInterpreter -> String -> RubyFunction4 -> IO (Either RubyError ()) Source #
registerGlobalFunction5 :: RubyInterpreter -> String -> RubyFunction5 -> IO (Either RubyError ()) Source #