In the lua programming language, I know that you can lock the metatable of userdata with the metamethod __metatable so that no-one can view the userdata's metatable with the getmetatable() function. But, I still want to access that metatable after its been locked. So, my question is, after the userdata's metatable is locked, is it still possible (maybe through some backdoor) to still get the metatable of the locked userdata, or is it just not possible (if so, then for what reasons)?
EDIT #1:
My motivation for wanting to know this is because I am trying to find a backdoor into Roblox's API so that I can more effectively script my games.
This applies at least to lua 5.3
In lua you can use the debug library method debug.getmetatable. That should return the original metatable regardless of the __metatable metamethod.
In C you can use the function lua_getmetatable for same purpose.
Also you could always make a variable somewhere to where you store the metatable and can access it later through that variable later.
Also if you used luaL_newmetatable, then you can still find the metatable in the registery with the metatable name you used.
You've stated you're using ROBLOX. When you think about it, they've locked this stuff for a reason. Why? Security purposes. Allowing scripters access to such things is dangerous and poses a serious threat. So the answer is no, once locked there is no way back into the metatable without a reference, because if there was the lock would be pointless.
ROBLOX also got rid of all functions in the debug library, but the recently added debug.traceback, so debug.getmetatable is definitely out of the question.
However, depending on your reasoning for this, there are others ways to accomplish the task. I'll go over some of them here:
1) If you want to set the metatable of an instance, make a fake instance using your own table, and then use __index and __newindex to control access to the object's properties and methods
2) If you want to set the metatable of a library, we follow the same approach as in 1, create a fake table and use __index to index the old table.
3) If you want to set the metatable of the global environment, set a new one with a pre-existing metatable. Make sure to use __index so the other variables still work!
As for simply reading the metatables, no you cannot do this.
In addition to that, if you lock your own tables, as mentioned earlier there is a way to access the metatable. Simply store a reference to it. The best way to do it would be make a local variable called meta in a do scope block.
I hope this answers your question, I tried to specifically target ROBLOX, since that's what your question was asking.
Related
Hello everyone!
I've been studying metamethods and I realized something strange!
I already know all the metamethods presented in the Lua documentation as __add, __index, __newindex, etc... But I see around in forums and in questions around here people using metamethods like __ev , __close, __group, and I have never seen anywhere else these metamethods be used or exist in any documentation.
My question is, these metamethods exists? and if not, how are they created? and why people create this metamethods?
anyway, thanks for the attention
These are custom metamethods and have special purpose in specific project or framework.
Metamethods are used to extend functionality of table or userdata. These are most usable to achieve OOP behavior.
Some programmers add custom metatables and metamethods for internal purpose and better readability, such as __super, __extend, __inherit. In most cases such metadata are used from standard metamethods as __index, __call, ... or from routine methods to cleanup objects, error handling and so on.
For example __close could be used with connection or file objects to manage them in predictible way, __gc can't be trusted for this purpose.
Example of __group usage: Lua metatables and metamethod - How to call a different member function
Status: Sort of solved. Switching Lua.Ref (close equivalent to LuaD LuaObject) to struct as suggested in answer has solved most issues related to freeing references, and I changed back to similar mechanism LuaD uses. More about this in the end.
In one of my project, I am working with Lua interface. I have mainly borrowed the ideas from LuaD. The mechanism in LuaD uses lua_ref & lua_unref to be able to move lua table/function references in D space, but this causes heavy problems because the calls to destructors and their order is not guaranteed. LuaD usually segfaults at least at the program exit.
Because it seems that LuaD is not maintained anymore, I decided to write my own interface for my purposes. My Lua interface class is here: https://github.com/mkoskim/games/blob/master/engine/util/lua.d
Usage examples can be found here:
https://github.com/mkoskim/games/blob/master/demo/luasketch/luademo.d
And in case you need, the Lua script used by the example is here:
https://github.com/mkoskim/games/blob/master/demo/luasketch/data/test.lua
The interface works like this:
Lua.opIndex pushes global table and index key to stack, and return Top object. For example, lua["math"] pushes _G and "math" to stack.
Further accesses go through Top object. Top.opIndex goes deeper in the table hierarchy. Other methods (call, get, set) are "final" methods, which perform an operation with the table and key at the top of the stack, and clean the stack afterwards.
Close everything works fine, except this mechanism has nasty quirk/bug that I have no idea how to solve it. If you don't call any of those "final" methods, Top will leave table and key to the stack:
lua["math"]["abs"].call(-1); // Works. Final method (call) called.
lua["math"]["abs"]; // table ref & key left to stack :(
What I know for sure, is that playing with Top() destructor does not work, as it is not called immediately when object is not referenced anymore.
NOTE: If there is some sort of operator to be called when object is accessed as rvalue, I could replace call(), set() and get() methods with operator overloads.
Questions:
Is there any way to prevent users to write such expressions (getting Top object without calling any of "final" methods)? I really don't want users to write e.g. luafunc = lua["math"]["abs"] and then later try to call it, because it won't work at all. Not without starting to play with lua_ref & lua_unref and start fighting with same issues that LuaD has.
Is there any kind of opAccess operator overloading, that is, overloading what happens when object is used as rvalue? That is, expression "a = b" -> "a.opAssign(b.opAccess)"? opCast does not work, it is called only with explicit casts.
Any other suggestions? I internally feel that I am looking solution from wrong direction. I feel that the problem reside in the realm of metaprogramming: I am trying to "scope" things at expression level, which I feel is not that suitable for classes and objects.
So far, I have tried to preserve the LuaD look'n'feel at interface user's side, but I think that if I could change the interface to something like following, I could get it working:
lua.call(["math", "abs"], 1); // call lua.math.abs(2)
lua.get(["table", "x", "y", "z"], 2); // lua table.x.y.z = 2
...
Syntactically that would ensure that reference to lua object fetched by indexing is finally used for something in the expression, and the stack would be cleaned.
UPDATE: Like said, changing Lua.Ref to struct solved problems related to dereferencing, and I am again using reference mechanism similar to LuaD. I personally feel that this mechanism suits the LuaD-style syntax I am using, too, and it can be quite a challenge to make the syntax working correctly with other mechanisms. I am still open to hear if someone has ideas to make it work.
The system I sketched to replace references (to tackle the problem with objects holding references living longer than lua sandbox) would probably need different kind of interface, something similar I sketched above.
You also have an issue when people do
auto math_abs = lua["math"]["abs"];
math_abs.call(1);
math_abs.call(3);
This will double pop.
Make Top a struct that holds the stack index of what they are referencing. That way you can use its known scoping and destruction behavior to your advantage. Make sure you handle this(this) correctly as well.
Only pop in the destructor when the value is the actual top value. You can use a bitset in LuaInterface to track which stack positions are in use and put the values in it using lua_replace if you are worried about excessive stack use.
I think I saw somewhere a native function in Lua that can return a new userdata. Does it exist? Is it possible to create custom userdata from normal Lua script?
You may be thinking of newproxy
From: http://lua-users.org/wiki/HiddenFeatures
newproxy is an unsupported and undocumented function in the Lua base
library. From Lua code, the setmetatable function may only be used
on objects of table type. The newproxy function circumvents that
limitation by creating a zero-size userdata and setting either a new,
empty metatable on it or using the metatable of another newproxy
instance. We are then free to modify the metatable from Lua. This is
the only way to create a proxy object from Lua which honors certain
metamethods, such as __len.
It was also useful for __gc metamethods, as a hack to get a callback when the newproxy instance becomes free.
This feature was present in Lua 5.1, but removed in 5.2. In Lua 5.2, __gc metamethods can be set on zero sized tables, so the main impetus for newproxy went away.
Actually no, in pure Lua.
The type userdata is provided to allow arbitrary C data to be stored in Lua variables. … Userdata values cannot be created or modified in Lua, only through the C API. This guarantees the integrity of data owned by the host program.
link
If you embed luaVM in host C/C++ application, you can export some function to create userdata to Lua, but it's not a good practice. UD is designed to be a blackbox for Lua scripts.
I am using Lua to extend my C++ application. My application have some parts(ex: timer event, ui events) that can be extended by Lua, so for each part, I make a new state and load files and functions related to that part in it, so making a change to a part and reloading it wont affect the other parts.
Now I am in a situation that I need some general files to be shared among all other parts.
like for example : I am making a function for the timer events part, and there is a object defined in those general files i want to change its info in this function.
Now i am in the ui event part and I need when i access that object in the general file I want it to contain the changes that was made from the ui part.
So I thought about creating another state for those and like make an __index for the global table in the other state to search this state if they don't find some stuff in it:)) apparently I don't know how to make that.
I hope someone get what I mean and tell me how to make that?!
Lua states created with lua_newstate or lua_newstate are completely separated and cannot directly talk to each other: you need to copy data manually from one state to the other.
You can set an __index metamethod for the global table in one state to look for the data in the other one, but you'll have to do it in C or export a function to Lua that does that.
When making Lua bindings for C++ classes, should I return tables or userdata objects?
Does anyone know any of the pros and cons for each method?
I recommend returning userdata. Regardless of approach, there has to be somewhere to put the pointer
to the C++ data, or the actual C++ data itself, and there's nowhere
safe to do this with a table.
Returning tables would make sense in some situations, because they can
be 'annotated' in Lua with extra attributes without one's having to do
anything extra to support this. Unfortunately the C++ object pointer
has to go somewhere, and there's nowhere sensible for it to go other
than an actual entry in the table itself.
This is not a very safe place for it to go. It can be found by Lua
code, and removed or replaced. This could be by accident, or on
purpose, it doesn't really matter.
My preference therefore is to return userdata objects. They can be
made to work like tables if one really must insist upon that, but they
also have a "secret" area (the actual userdata itself) where the C++
object pointer can be stored, safe from overwriting by Lua code.
(Userdata objects also have an "environment" pointer, which is another
place to store object-specific data. As with the userdata payload
itself, this value is inaccessible to Lua code and can't be damaged
that way.)