[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Safe metamethod handling
- From: Mark Hamburg <mhamburg@...>
- Date: Fri, 19 Sep 2003 10:24:47 -0700
I'm looking into how to make proxied tables or userdata or related items
behave more like regular tables. This, however, seems to require metamethods
for a variety of functions like table.insert, pairs (or next), etc.. Not a
big deal. We just override those functions with code that checks for the
metamethod and uses it in preference to the old code if it exists.
Except...
I note that part of the pattern in things like Lunar is to use the
__metatable key to protect the metatable for the object. This would then
inhibit Lua code from looking in the metatable which would thwart the whole
enterprise.
Work arounds I've thought of...
* Introduce "getmetamethod" which ignores the __metatable key and does the
standard metatable lookup as documented in the manual; i.e.:
function getmetamethod( obj, event )
return rawget( metatable(obj) or {}, event )
end
The downside here is that now it's possible to call metamethods when they
aren't supposed to be called or to call them with the wrong parameters. In
other words, it's a potential security hole.
* Introduce "callmetamethod" which could at least insure that the first
parameter was the object. For example:
function callmetamethod( obj, event, default, ... )
local metafunc = rawget( metatable(obj) or {}, event );
if metafunc then
return metafunc( obj, unpack( arg ) )
else
return default( obj, unpack( arg ) )
end
end
* Treat the cases where it's interesting as methods on the object instead of
metamethods. For example:
local oldRemove = table.remove;
table.remove = function( t, pos )
local removeMethod = t.remove or oldRemove;
return removeMethod( t, pos )
end
This avoids writing anything in C to get around the __metatable tag. The
nice thing about that option is that now we can use object-syntax to invoke
the routines. But it breaks being able to write:
setmetatable( t, table )
Since that would create a cycle for remove. We could get around the cycle by
detecting it in the code for remove, but that gets tricky if there might be
other patches on table.remove.
I think I'm inclined toward callmetamethod with special protection for the
__gc method -- i.e., prevent it's use for event == "__gc". I think all of
the other standard metamethods can be invoked via the normal Lua code and
hence this shouldn't open up any other security holes.
Any comments or feedback from those more experienced in the issues? Is there
something simple that I'm just missing?
Thanks.
Mark