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

Why does setfenv protect the global table?

Started by Pharap, 18 May 2013 - 07:08 PM
Pharap #1
Posted 18 May 2013 - 09:08 PM
Why does setfenv protect the global table by default?
Surely it would make more sense to let it change the global table and have CraftOS create a sandboxed version?
Grim Reaper #2
Posted 18 May 2013 - 10:39 PM
Why would it make more sense for setfenv() to modify the global table and have CraftOS create a sandboxed version? I don't quite understand your query in that setfenv() is a method of sandboxing functions.
Pharap #3
Posted 18 May 2013 - 11:25 PM
Why would it make more sense for setfenv() to modify the global table and have CraftOS create a sandboxed version? I don't quite understand your query in that setfenv() is a method of sandboxing functions.

Because otherwise you can't just change the global table in a single call to setfenv.
If they were to make setfenv accept 0 as the global thread and allow you to change it's _G it would be helpful, then (assuming it doesn't allow this for a reason) just set up a setfenv that sandboxes that feature out, like getmetatable stop you accessing the string metatable.
Grim Reaper #4
Posted 18 May 2013 - 11:33 PM
I still don't think I quite understand what you're asking. I'm familiar with setfenv() and the like, but I don't understand this part:

Because otherwise you can't just change the global table in a single call to setfenv.
Pharap #5
Posted 18 May 2013 - 11:38 PM
I still don't think I quite understand what you're asking. I'm familiar with setfenv() and the like, but I don't understand this part:

Because otherwise you can't just change the global table in a single call to setfenv.

If you call setfenv(0,{}) it should change the environment of the master thread from the contents of _G to an empty table, but for some reason it gives the error "lua 52: cannot change environment of given object". Even if I'm wrong about the 'running thread' being the absolute master thread containing _G (though I'm pretty sure it is, I haven't run the getfenv(0) == _G thing in a sandboxed function yet) that's unexpected behaviour if you're going by the official lua docs: http://www.lua.org/manual/5.1/manual.html#pdf-setfenv
Grim Reaper #6
Posted 18 May 2013 - 11:43 PM
The reason for this is that you can't change the environment of the calling function from the called function. The environment of a function can only be called from the calling function, if I'm not mistaken.
Pharap #7
Posted 18 May 2013 - 11:54 PM
The reason for this is that you can't change the environment of the calling function from the called function. The environment of a function can only be called from the calling function, if I'm not mistaken.

Hrm, that's rather odd. I'll assume your right, it sounds legit.
It must be a LuaJ specific error since the Lua docs make no mention of this issue.
Oh well, this is why I asked in the 'ask a pro' thing and not the bug thing, I thought it would be an annoying explanation like that.

The reason I asked is because I'm developing a CC-OS and as part of it I'm completely tearing out _G and replacing all it's contents with my own functions (most are the old functions renamed to my liking). I really wanted to be able to do it at the highest level for debugging purposes ie then I could do it by running it through the shell and having any program that runs afterwards run in the same environment without me having to fiddle around too much.
I can get around it, it's just annoying that I can't do it as lazily as I'd like.
Thanks anyway.
Grim Reaper #8
Posted 18 May 2013 - 11:57 PM
The reason for this is that you can't change the environment of the calling function from the called function. The environment of a function can only be called from the calling function, if I'm not mistaken.

Hrm, that's rather odd. I'll assume your right, it sounds legit.
It must be a LuaJ specific error since the Lua docs make no mention of this issue.
Oh well, this is why I asked in the 'ask a pro' thing and not the bug thing, I thought it would be an annoying explanation like that.

The reason I asked is because I'm developing a CC-OS and as part of it I'm completely tearing out _G and replacing all it's contents with my own functions (most are the old functions renamed to my liking). I really wanted to be able to do it at the highest level for debugging purposes ie then I could do it by running it through the shell and having any program that runs afterwards run in the same environment without me having to fiddle around too much.
I can get around it, it's just annoying that I can't do it as lazily as I'd like.
Thanks anyway.

I found this for you:
"You can change the environment of a function with the setfenv function (set function environment). It receives the function and the new environment. Instead of the function itself, you can also give a number, meaning the active function at that given stack level. Number 1 means the current function, number 2 means the function calling the current function (which is handy to write auxiliary functions that change the environment of their caller), and so on."

From the luadocs on non-global environments.

If you really want to start at the top (or bottom, rather) of the stack in terms what programs are being executed in CC so that you have control over things such as the global table, you might want to look into injecting your program on top of the shell. To do this you'll need to locate the main shell program through getfenv() and call exit() on that object. If you want, I could provide a code example of this for you. However, you might want to search the forums because I think that's where I learned of this technique first. It was used for writing a totally-in-control key logger or something of the sort because it ran on top of the shell and dispatched events to it and all programs below it.
Pharap #9
Posted 19 May 2013 - 12:03 AM
I found this for you:
"You can change the environment of a function with the setfenv function (set function environment). It receives the function and the new environment. Instead of the function itself, you can also give a number, meaning the active function at that given stack level. Number 1 means the current function, number 2 means the function calling the current function (which is handy to write auxiliary functions that change the environment of their caller), and so on."

From the luadocs on non-global environments.

If you really want to start at the top (or bottom, rather) of the stack in terms what programs are being executed in CC so that you have control over things such as the global table, you might want to look into injecting your program on top of the shell. To do this you'll need to locate the main shell program through getfenv() and call exit() on that object. If you want, I could provide a code example of this for you. However, you might want to search the forums because I think that's where I learned of this technique first. It was used for writing a totally-in-control key logger or something of the sort because it ran on top of the shell and dispatched events to it and all programs below it.

The first bit I knew as it's stated in the lua docs.
I'm guessing by the second one there is a way to do it with setfenv, but it would probably mess up the shell, in which case I'm probably just better off making a program that can run things in my new environment by dumping the environment onto a global variable then running a program in that environment.
Pretty much just change one line of my current program then make a program that just calls os.run using that environment on the program.
(yes, that is genuinely more effort than being able to do it in one line with setfenv lol)