lua-users home
lua-l archive

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


Roberto Ierusalimschy wrote:

A safe alternative, that does not use strcmp, is to write versions of luaL_newmetatable and luaL_checkudata that use pointers as keys, instead of strings:

LUALIB_API int luaL_newmetatable_pointer (lua_State *L, void *tname) {
  lua_pushlightuserdata(L, tname);
  lua_rawget(L, LUA_REGISTRYINDEX);  /* get registry.name */
  if (!lua_isnil(L, -1))  /* name already in use? */
    return 0;  /* leave previous value on top, but return 0 */
  lua_pop(L, 1);
  lua_newtable(L);  /* create metatable */
  lua_pushlightuserdata(L, tname);
  lua_pushvalue(L, -2);
  lua_rawset(L, LUA_REGISTRYINDEX);  /* registry.name = metatable */
  lua_pushvalue(L, -1);
  lua_pushstring(L, tname);
  lua_rawset(L, LUA_REGISTRYINDEX);  /* registry[metatable] = name */
  return 1;
}

LUALIB_API void *luaL_checkudata_pointer (lua_State *L, int ud, void *tname) {
  void *tn;
  if (!lua_getmetatable(L, ud)) return NULL;  /* no metatable? */
  lua_rawget(L, LUA_REGISTRYINDEX);  /* get registry[metatable] */
  tn = lua_touserdata(L, -1);
  if (tn && (tn == tname)) {
    lua_pop(L, 1);
    return lua_touserdata(L, ud);
  }
  else {
    lua_pop(L, 1);
    return NULL;
  }
}

Always profile first, of course, to see if it's worth the trouble.

--
Fabio Mascarenhas

     if( !lua_getmetatable( L, index ) )
         return NULL;
     lua_pushlightuserdata( L, udkey );      /* ( ... mt udkey )
     lua_rawget( L, -2 );                    /* ( ... mt mt[ udkey ] )


This technique is not safe. A Lua program may get udkey (traversing the
metatable of a userdata) and then add it as a key in the metatable of a
userdata from a different kind, fooling checkudata.

-- Roberto