This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
hbomb79's profile picture

os.run sandbox

Started by hbomb79, 27 August 2015 - 11:26 PM
hbomb79 #1
Posted 28 August 2015 - 01:26 AM
Hey guys, hit a little snag. I am attempting to run a program using os.run and a sandbox, which is working great. Although I need it so that the error is caught, not displayed and then left there.

I would love it to be the same as pcall as in ok, err (ok boolean, err string).

From what I understand loadstring and dofile can be used, but I don't know how to keep the sandbox.

Here is the sandbox so far (not done):

local oTerm = term.current()

local term = { -- new term
    write = function()
      --# here, we actually handle the write. ANY call to write will come here, not the BIOS. Unlike term.redirect.
    end,
    setBackgroundColor = function() end,
    setBackgroundColour = function() end,
    setTextColor = function() end,
    setTextColour = function() end,
    getSize = function() end,
    setCursorBlink = function() end,
    getPos = function() end,
    reposition = function() end
}
local protected = { --# the new programs environment (added to default so override anything you don't want usable)
    term = term,
    write = term.write --# "redirect any shortcuts."
}
setmetatable( protected.term, {__index = oTerm}) --# If we did not create a block/redirect for a term command in our new term object, then redirect the request to the original term.

local ok = os.run( protected, "test.lua" )
if not ok then
    print("This program has crashed! \nPress any key to continue")
    os.pullEvent("key")
elseif ok then
    print("This program has finished.\nPress any key to continue")
    os.pullEvent("key")
end
*apologies for identation, it looks fine in Notepad++ and Sublime Text :/

If you know a better way of doing a sandbox then please let me know, this is my first attempt at one and I am not sure if there is a hidden workaround. it is essentially designed to redirect all term calls to my own functions, term.redirect is no good for my purpose as I am using multitasking and cannot figure out an elegant way of stopping programs altering other windows (getting off topic now).

So essentially, how do I call a program, with a sandbox like what explained above (redirects desired functions to my own (entire term library, print and write)) where I can also catch the error, much like a pcall on a function. I kind of know how to get a program into a function, but not with a sandbox.

local ok, err = pcal(func)
if not ok and err then
	-- Good looking error screen explaining what went wrong
end


Thanks in advance.
Edited on 27 August 2015 - 11:28 PM
Bomb Bloke #2
Posted 28 August 2015 - 02:06 AM
If you loadfile/loadstring your code into a function, you should be able to setfenv() your desired environment table against it before pcall'ing it.

In CC 1.74, Dan's Lua 5.2 "compatibility layer" code allows calling loadfile in the format of "loadfile( string filename, table environment )".
hbomb79 #3
Posted 28 August 2015 - 03:25 AM
Can I pcall the 1.74 loadstring? Or is it the same as os.run where it only returns true or false?
Bomb Bloke #4
Posted 28 August 2015 - 03:40 AM
The idea is that you don't pcall loadstring, but rather you pcall the function that loadstring returns. After checking that a function was returned, of course: if the code can't be compiled, loadstring will return false and an error, same as pcall does if the code can't be executed.
hbomb79 #5
Posted 28 August 2015 - 05:51 AM
So I should check if set and get fenv are available, if so then load the string into a function and pcall it. If they are not available then I will assume they are running CC 1.74 and use loadstring with the env passed in there.

Skeleton Layout:

if setfenv and getfenv and type(getfenv) == "function" and type(setfenv)=="function" then
    --# load file into function and setfenv. Stop new func in pg
else
    --# load file into function and set function environment using the loadstring argument. Store new func in pg
end
--# call the new function
local ok, err = pcall(pg)
if not ok and err then
--# error
end
hbomb79 #6
Posted 28 August 2015 - 07:08 AM
Works beautifully, thanks for the speedy reply and concise answer, exactly what I wanted.
Bomb Bloke #7
Posted 28 August 2015 - 07:35 AM
So I should check if set and get fenv are available, if so then load the string into a function and pcall it. If they are not available then I will assume they are running CC 1.74 and use loadstring with the env passed in there.

Well, sorta, yeah.

The one misconception (which I sorta get the impression hasn't only impressed itself on you) is that 1.74 doesn't disable getfenv/setfenv. It sorta sets things up for their eventual removal, but at its core, it's still Lua 5.1, only you can use 5.2 syntax in places. Still no "goto", though…

(Personally, I'd rather things stay as they are: having support for both versions seems like a better option to me then only supporting one, and I'm not sure what benefits 5.2 brings to the table to justify the massive break in backwards compatibility a complete jump would make.)

In any case, what you're doing should work and future-proof your code as well.
hbomb79 #8
Posted 28 August 2015 - 09:48 AM
Ah, I was a little confused at that. After looking through the BIOS I saw that the functions were still there and assumed they were kept for backwards compatibility.

(Personally, I'd rather things stay as they are: having support for both versions seems like a better option to me then only supporting one, and I'm not sure what benefits 5.2 brings to the table to justify the massive break in backwards compatibility a complete jump would make.)
I agree with you

I shall keep the backwards compatibility, I have just integrated this with coroutines (which I have not used before either) and its going surprisingly well.

Thanks for clearing up my confusion