Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Copy a table and keep its metatables?

Hello, I'm making a script sandbox and i want to know if there's any good way of copy a table and keep its metatables, i'm just leaving the table part, not the entire wrap function, here is the code:

function wrap(real)
local fake = {}
for i,v in next,real do
fake[i] = wrap(v)
end
return fake
end

Now i know that i can do this

function wrap(real)
local fake = {}
for i,v in next,real do
fake[i] = wrap(v)
end
fake = setmetatable(fake,getmetatable(real))
return fake
end

But if they lock the metatable i can not keep the metatables. In my other post someone said i can try to copy the behaviour of the metatable, but i don't know how i can do that. Help would be appreciated! :D

4 comments

0

The problem is that the metatable can be locked with the __metatable metamethod

0

@kingdom5

1

fake setmetatable + remove __metatable field

1 answer

✓ Accepted answer

Issues

Copy a table and keep its metatables? But if they lock the metatable i can not keep the metatables.

Solution

My solution is based off the assumption that the inputted code can have its environment sandboxed without exposing the true environment to the sandboxed environment.

You should have the ability to overwrite the environment they're allowed to access through getfenv and setfenv so you should be able to just create a wrapped setmetatable method that removes any __metatable field for a passed metatable.

To avoid the issue of them overwriting what you tried via __newindex or __index I suggest using rawset.

Pseudo Code

Create reference to the old setmetatable; create a new setmetatable that sets the __metatable field of the passed metatable to nil; then return the result of setting the metatable to the object via the reference to the original setmetatable (trueSetMetaTable).

In this case updateEnvironment would be some predefined method to add your new setmetatable to the sandboxed function environment.

local trueSetMetaTable = setmetatable

local function setmetatable(object, metatable)
	rawset(metatable, "__metatable", nil)
		
	return trueSetMetaTable(object, metatable)
end

updateEnvironment(setmetatable)

2 comments

0

Thanks a lot! Now i can make it work and i can even wrap it and then set the __metatable to the fake value, this helped a lot :D

0

You're welcome!

This discussion is preserved as it was. New answers, comments, and votes are closed.