generic image
Processing...
  • Games
  • Catalog
  • Develop
  • Robux
  • Search in Players
  • Search in Games
  • Search in Catalog
  • Search in Groups
  • Search in Library
  • Log In
  • Sign Up
  • Games
  • Catalog
  • Develop
  • Robux
   
ROBLOX Forum » Game Creation and Development » Scripters
Home Search
 

Re: Read-only tables

Previous Thread :: Next Thread 
noliCAIKS is not online. noliCAIKS
Joined: 08 Mar 2010
Total Posts: 917
11 Jan 2013 10:20 AM
A while ago, someone claimed it was impossible for normal users to make read-only tables in ROBLOX.
Today, I prove them wrong.

-- create a closure
do
-- store global functions locally to prevent hacking
local error = error
local getmetatable = getmetatable
local newproxy = newproxy
-- show error message on attempt to modify a read-only table
local function ModificationError()
error("can't modify this table")
end
function CreateReadonlyTable(contentTable)
local proxy = newproxy(true)
local metatable = getmetatable(proxy)
metatable.__index = contentTable
metatable.__metatable = "The metatable is locked"
metatable.__newindex = ModificationError
return proxy
end
end

Boolean = CreateReadonlyTable({
False = 0,
True = 1
})

There you go!
Report Abuse
xXxMoNkEyMaNxXx is not online. xXxMoNkEyMaNxXx
Joined: 03 Oct 2008
Total Posts: 3120
11 Jan 2013 10:25 AM
Wat do now nubs
jejejejejejejje
Report Abuse
SCARFACIAL is not online. SCARFACIAL
Joined: 28 Jan 2010
Total Posts: 7970
11 Jan 2013 12:34 PM
That's not a table.
That's a read-only userdata.
Report Abuse
noliCAIKS is not online. noliCAIKS
Joined: 08 Mar 2010
Total Posts: 917
11 Jan 2013 01:47 PM
The "coroutine", "math", "string" and "table" libraries are read-only userdata's as well in ROBLOX.
I don't think it counts.
Report Abuse
Seranok is not online. Seranok
Joined: 12 Dec 2009
Total Posts: 11083
11 Jan 2013 03:04 PM
print(type(Vector3)) --> "table"
Vector3.new = nil --> error
Report Abuse
Luc599345 is not online. Luc599345
Joined: 25 Jul 2008
Total Posts: 1169
11 Jan 2013 03:15 PM
You can't change functions in tables that are the same in every scripts' environments. If you COULD edit it, you could just overwrite the Vector3.new function and whenever another script would call it, it'll run your function instead. This exploit was found by popinman, which later reported it to the admins. Which is why, now, you cannot overwrite those functions.
Report Abuse
noliCAIKS is not online. noliCAIKS
Joined: 08 Mar 2010
Total Posts: 917
11 Jan 2013 03:17 PM
Oh, and what's more?
print(getmetatable(Vector3)) --> "nil"
print(rawget(Vector3, "new")) --> function: ********
print(pcall(rawset, Vector3, "new", "hax")) --> false Attempt to modify a readonly table
Report Abuse
ColorfulBody is not online. ColorfulBody
Joined: 17 Jun 2012
Total Posts: 2353
11 Jan 2013 07:07 PM
The person who claimed that was probably me, and I was right. What you made is a read-only userdata, as Sorcus pointed out.

Read-only tables do not exist in normal Lua, they only exist in ROBLOX. An example of them is the Vector3 table or the Instance table. They're read-only, but their type is still 'table'. It is impossible to reproduce that behavior.

Obviously, you can create an userdata that behaves somewhat as a table and is read-only, but it's still an userdata and not a table.
Report Abuse
Luc599345 is not online. Luc599345
Joined: 25 Jul 2008
Total Posts: 1169
11 Jan 2013 07:32 PM
"as Sorcus pointed out."

I can't tell if SCARFACIAL is just a successful wanna-be or Julien is joking o.O
Report Abuse
ColorfulBody is not online. ColorfulBody
Joined: 17 Jun 2012
Total Posts: 2353
11 Jan 2013 07:39 PM
@Luc599345

I'm just joking, obviously. He doesn't actually look like Sorcus, and it's obvious by his posts that he's not Sorcus.
Report Abuse
1smurf1 is not online. 1smurf1
Joined: 07 Aug 2010
Total Posts: 50
11 Jan 2013 11:28 PM
read only table?

ReadOnly = function()
return setmetatable({}, {
__newindex = function() print"This is a read-only table!" end,
__metatable = "This metatable is locked!"})
end

readTab = ReadOnly()

table = { remove = table.remove, sort = table.sort, unpack = table.unpack, concat = table.concat }
function table:insert(arg1, arg2)
if not(arg2) then
self[#self + 1] = arg1
else
if type(arg1) ~= "number" then error("number expected, got string", 2) end
for i = #self, arg1, -1 do
self[i + 1] = self[i]
end
self[arg1] = arg2
end
end
rawset = function(self, i, v)
self[i] = v
end
Report Abuse
ColorfulBody is not online. ColorfulBody
Joined: 17 Jun 2012
Total Posts: 2353
11 Jan 2013 11:43 PM
@1smurf1

That still isn't a read-only table. You can change its values with rawset. Yes, I know, you replaced the rawset variable, but it still isn't read-only, because, if you had access to rawset, you could change it.
Report Abuse
1smurf1 is not online. 1smurf1
Joined: 07 Aug 2010
Total Posts: 50
11 Jan 2013 11:52 PM
oh and you could change it with table.insert too - ignoring the fact that the code is meant to be placed at the top of a script. . .
Report Abuse
ColorfulBody is not online. ColorfulBody
Joined: 17 Jun 2012
Total Posts: 2353
12 Jan 2013 12:14 AM
@1smurf1

Read-only tables CAN be changed with table.insert. Try it with the Vector3 or the Instance tables.
Report Abuse
1smurf1 is not online. 1smurf1
Joined: 07 Aug 2010
Total Posts: 50
12 Jan 2013 12:32 AM
did i not just say that?
i'm saying that the case you made - "it still isn't read-only, because, if you had access to rawset, you could change it" - doesn't apply since you don't have access to rawset/table.insert if you put the code where its *supposed* to be (at the top of the script)
Report Abuse
ColorfulBody is not online. ColorfulBody
Joined: 17 Jun 2012
Total Posts: 2353
12 Jan 2013 01:31 AM
I actually can still have access to rawset if another script put a reference to it in _G, since I can access that reference. Overwriting variables is cheating and does not apply.
Report Abuse
xXxMoNkEyMaNxXx is not online. xXxMoNkEyMaNxXx
Joined: 03 Oct 2008
Total Posts: 3120
12 Jan 2013 02:19 AM
wat do now smurf guy
Report Abuse
SN0X is not online. SN0X
Joined: 24 Oct 2011
Total Posts: 7277
12 Jan 2013 03:00 AM
ya wat do
Report Abuse
kirkyturky12 is not online. kirkyturky12
Joined: 30 Apr 2010
Total Posts: 1915
12 Jan 2013 09:21 AM
Olololol.


    local OldType = type
    local Proxies = {}
    
    local GetInTable = function(tab,val)
        for i,v in pairs(tab) do
            if v == val then
                return i
            end
        end
    end
    
    local type = function(Val)
        if GetInTable(Proxies,Val) then
            return "table"
        else
            return OldType(Val)
        end
    end
    
    local Tab = {
        Hi = "Yar",
        Derp = "Ummmm",
    }
    
    local NewIndex = function()
        error("lolno")
    end
    
    local Metatable = "Locked."
    
    local Prox = newproxy(true)
    local Meta = getmetatable(Prox)
    Meta.__index = Tab
    Meta.__newindex = NewIndex
    Meta.__metatable = Metatable
    table.insert(Proxies,Prox)
    
    Tab = Prox
    
    print(type(Tab))
    print(Tab.Hi)
    Tab.Derp = "dfdfdf"
    print(Tab.Derp)


Report Abuse
Seranok is not online. Seranok
Joined: 12 Dec 2009
Total Posts: 11083
12 Jan 2013 10:35 AM
Lua's built-in type function should return "table" when called with the table
Report Abuse
noliCAIKS is not online. noliCAIKS
Joined: 08 Mar 2010
Total Posts: 917
12 Jan 2013 11:25 AM
Just noticed an actual issue caused by this...

local proxy = newproxy(true)
local meta = getmetatable(proxy)
meta.__index = {var1 = 1234}
local object = setmetatable({}, proxy) -- bad argument #2 to 'setmetatable' (nil or table expected)
Report Abuse
booing is not online. booing
Joined: 04 May 2009
Total Posts: 6594
12 Jan 2013 12:21 PM
setmetatable(_G, { __index = {}, __newindex = error })
Report Abuse
1smurf1 is not online. 1smurf1
Joined: 07 Aug 2010
Total Posts: 50
12 Jan 2013 12:56 PM
Since when were there rules in scripting. . .
I overwrote table, I overwrote rawest, ill just overwrite _G (like stated above)

Is the idea of a read only table that hard for you to wrap your head around?
Report Abuse
Seranok is not online. Seranok
Joined: 12 Dec 2009
Total Posts: 11083
12 Jan 2013 02:09 PM
But it's still technically not a table...
Report Abuse
ColorfulBody is not online. ColorfulBody
Joined: 17 Jun 2012
Total Posts: 2353
12 Jan 2013 06:31 PM
"I overwrote table, I overwrote rawest, ill just overwrite _G (like stated above)"

Well, the table will still not be read-only no matter what you do.

I'm going to take a script and use that script to insert the rawset function into the Vector3 table, which is read-only. I'll insert it under a numerical key, since that's all the table.insert function allows you to do.

Then, in the script, I'll get the rawset function from the Vector3 table in the correct index (an index which you cannot guess, since it could be any numerical value) and use it to edit your table.

You could iterate through the Vector3 table, find the index and remove it using table.insert, though. But you'd need to do it with Instance, BrickColor, Region3, Vector3int16 and all the other read-only tables.

Oh, and don't forget I can also put it in shared instead of _G. As for overwriting their metatables, what if the other script overwrites them first?

Basically, as long as the two scripts can communicate in any way with each others, I can give it back all the functions you overwrite.

Even if you actually made it impossible to use a read-only table or shared or _G by removing all of them, I could still add the function back in a read-only table every frame. So you'd need to run the loop that removes all the functions from these tables every single frame. Oh, and you'd need to do it with the Spawn function or in a coroutine (or in an event), because you don't want to interrupt the script.

So by that point, you overwrote the rawset function, shared and _G. You also have around 10 coroutines or threads running permanently, iterating through all the read-only tables every frame and removing all the numerical values from them. Great.

But I can still communicate through the game hierarchy. I can create a BindableFunction that points to the rawset function. And I can put it anywhere in the game.

So, to prevent me from doing that, you'd need to scan through the entire game hierarchy every single frame in a coroutine or a thread and remove all BindableFunctions. And BindableEvents too, because I could also do it with BindableEvents.

Now, to recapitulate, you have:
- Overwritten the rawset function
- Overwritten _G and shared
- A thread or coroutine iterating every frame through all the read-only tables and removing numerical values from them
- A thread or coroutine iterating every frame through the whole game hierarchy to remove BindableFunctions and BindableEvents

Not yet convinced? Ok. I have also thought about inserting the bindable object in the CoreGui using InsertService::Insert, in which case you'd need to brute-force the FindFirstChild function in a thread every frame to find it, and in which case you couldn't even remove it anyway, but the script wouldn't be able to access it and invoke it.

There's also the idea of making the script do something when an event on a service (like the Changed event, in which case the script would have to change the name property), but that doesn't make it possible to pass tables.

There are also some other things I could do that would work, but it'd be ridiculous to even mention them. Let's say I now use the environment of a function in one of the ROBLOX libraries (RbxLibrary) to make the two scripts communicate. Or no, let's say I actually get the environment of a such function and call the rawset function directly from there. Unless you actually decide to change the environment of every single library function ROBLOX provides, I don't think you can do much.

Ok, let's stop with all this theoretical madness, because, anyway, you can prevent me from accessing the game hierarchy, the read-only tables and the ROBLOX libraries.

Let's pretend you just set every single default variable to nil. Well, congratulations, the script is now completely useless and non-functional because all it can do is play with syntax. But yes, it cannot edit the table. That's cool, but the script cannot access anything and all it can do is create tables, strings and numbers and manipulate them in whatever way using loops or operations. That's just useless, though.

So yes, you made a table that cannot be edited by indexing it using the syntax, and you made sure it could not be used in any other way by removing every single function whatsoever from the environment. Even then, there are some other ways to get the default environment back, but you'll probably find some way to prevent those too.

And yet, your table is still not a read-only table. It cannot be edited by that particular script because you removed everything from its environment, but it's still not a read-only table, because if we had access to those default functions, we could edit the table. Editing everything other than the table doesn't make the table different, it just makes everything else different. Therefore, the table is still as it was before you removed everything from the environment, and, thus, it cannot have become read-only.

Even then, to make this system useful in whatever way, you'd need to be able to make the script unable to detect whether you edited anything. You'd need to be able to make it unable to know whether the table is really read-only or whether it's a fake read-only table. To do that, you'd... huh... basically need to re-implement everything in the environment that can be used in any way to edit the table, while making sure it still functions in the same way. But, if you overwrite functions, then the script can detect it, since it's possible, with string.dump, to know if a function is a C function or a Lua function. So you'd need to overwrite the string.dump function too. In fact, your code would just get overly complex, and you'd end up needing over 5000 lines of code only to make sure the script cannot detect whether a table is a real read-only table or not.

In the end, you might as well just write your own Lua interpreter in Lua with read-only tables and every single other feature supported by Lua. It'd be a more proper solution, and I assure you that it would be more useful.

Oh, and, remember, even by that point, the table wouldn't be really read-only, because, if we had access to the default functions, we could still edit it.
Report Abuse
Previous Thread :: Next Thread 
Page 1 of 1
 
 
ROBLOX Forum » Game Creation and Development » Scripters
   
 
   
  • About Us
  • Jobs
  • Blog
  • Parents
  • Help
  • Terms
  • Privacy

©2017 Roblox Corporation. Roblox, the Roblox logo, Robux, Bloxy, and Powering Imagination are among our registered and unregistered trademarks in the U.S. and other countries.



Progress
Starting Roblox...
Connecting to Players...
R R

Roblox is now loading. Get ready to play!

R R

You're moments away from getting into the game!

Click here for help

Check Remember my choice and click Launch Application in the dialog box above to join games faster in the future!

Gameplay sponsored by:
Loading 0% - Starting game...
Get more with Builders Club! Join Builders Club
Choose Your Avatar
I have an account
generic image