lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Okay maybe I can grep for some of it -- I looked for "->env" and ".env":

LUA_API void lua_getuservalue (lua_State *L, int idx):
./lapi.c:  if (uvalue(o)->env) {
./lapi.c:    sethvalue(L, L->top, uvalue(o)->env);

This is not used elsewhere in Lua's core, it's exposed for the CAPI...

LUA_API void lua_setuservalue (lua_State *L, int idx):
./lapi.c:    uvalue(o)->env = NULL;
./lapi.c:    uvalue(o)->env = hvalue(L->top - 1);

Not used -- exposed for the CAPI..

static void reallymarkobject (global_State *g, GCObject *o):
./lgc.c:      markobject(g, gco2u(o)->env);

I assume this makes sure the associated env table gets collected with the "host" userdata.

LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e):
./lstring.c:  u->uv.env = e;

This is only used inside lua_newuserdata() in lapi.c.  It always provides NULL as the third arg that gets assigned to the userdatas' env Table pointer.

So now I'm really curious because I can't seem to find anywhere else the env Table pointer is used on a userdata.  This is either intended or something historic?

If the env reference is *only* to tie a table to a userdata for GC collection, then my original suggestion could be done without affecting anything.  I think setuservalue() should allow you to associate a table *or* userdata with a userdata for GC collection.  That is what I would like to see for 5.3.

Let the disagreements flow :p



On Tue, Dec 3, 2013 at 10:06 PM, Sir Pogsalot <sir.pogsalot@gmail.com> wrote:
Well, when I was talking about this in #lua on Freenode I imagined a scenario where someone would break out of a sandbox to get at debug.setmetatable() and then cause a segfault.  I was just trying to get across the point that I'd rather have someone get at os.exit() than cause a segfault -- as you may have atexit() or on_exit() handlers or some other form of cleanup you want to happen.  A segfault kind of prevents that..

Anyway -- a lot of people seem to disagree with me that a segfault should be guarded against.  I've heard arguments that asserting the type with checkudata() and also the size of the userdata before accessing members would make code inefficient -- and that my worries about people causing segfaults through the debug library are unfounded as you can just make all references to the debug library disappear, etc...  Sean said earlier that that there are 0 uses of rawlen() or objlen() in Lua's core used for the sort of checking I was talking about -- I'm assuming he's advocating this because upstream doesn't do it?  I still disagree but all of this is kind of disconnected from what I was talking about in my original posting.

typedef union Udata {
  L_Umaxalign dummy;  /* ensures maximum alignment for `local' udata */
  struct {
    CommonHeader;
    struct Table *metatable;
    struct Table *env;
    size_t len;  /* number of bytes */
  } uv;
} Udata;

Now you see, there are 2 fields/members in the userdata struct.  One for the metatable and one for the environment.  debug.setmetatable() sets the metatable pointer, not the env pointer.  What I want is not easily possible without changing the definition of the Udata struct -- so I've given up on that since I like Roberto's idea to just contain all userdatas within one shared env table. :-)  lua_get/setuservalue() set the env pointer, the Table pointer.

Does anyone happen to know where else the env pointer is used?  What other parts of Lua make use of it and why?  I can't easily grep for 'env' and find out.  Is this something historic from previous versions of Lua?  I must be missing something obvious, but what is the env table on a userdata for?  As far as I see it's simply for use with get/setuservalue(), to make a GC association.  That's already very useful, but does it affect the use of the userdata elsewhere?


On Tue, Dec 3, 2013 at 9:48 PM, David Heiko Kolf <david@dkolf.de> wrote:
Sir Pogsalot wrote:
> Maybe this is just something that was drilled into me from a young
> age but I've always operated under the "libraries should never
> assert() or segfault" mindset.  Also, users are sometimes directly
> scripting in Lua -- WoW, awesome window manager people, Garry's Mod,
> Android game creation apps/frameworks, etc...  Sandboxed environments
> maybe, but still directly working with library functions.  I don't
> think I'm being overzealous by calling this minimal amount of
> 'defensive programming' necessary :>  Also lua_objlen() existed in
> 5.1 -- and it pains me daily to think how many libraries out there
> only luaL_checkudata() and blindly access members.  Thanks for
> contributing to my early death :<

The only way for a script user to change the metatable for userdata
would be to use the debug library. The normal setmetatable function only
works on unprotected tables. And the debug library comes with this warning:

<http://www.lua.org/manual/5.2/manual.html#6.10>:
> You should exert care when using this library. Several of its
> functions violate basic assumptions about Lua code (e.g., that
> variables local to a function cannot be accessed from outside; that
> userdata metatables cannot be changed by Lua code; that Lua programs
> do not crash) and therefore can compromise otherwise secure code.

So for my modules I would use almost the same pattern as for the default
file module and just check the metatable. If somebody had taken this
metatable and used debug.setmetatable to put it on some different
userdata -- well, they would *want* their application to crash. I cannot
imagine how you would do this on accident. Executing foreign code is a
different matter, but it wouldn't make a lot of sense to expose the
debug module in a sandbox.

Best regards,

David Kolf