lua-users home
lua-l archive

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


Lua 5.1 has a very annoying issue with its module system. The module()
function always sets _G[modulename]. But this _G is of the main
environment, and not always the _G of the code loading the module.
Meaning that in sandboxes, or in modules that don't use
package.seeall... you won't be able to load the module (unless it
happens to return itself). And code that isn't interested in the
module suddenly gets a global from nowhere landed in its environment.

My proposal for a fix (a perfect candidate for 5.2 IMHO) would be to
switch the responsibilities of module() and require(). module() (and
luaL_register) would continue to modify the environment, and set
package.loaded[modulename]. But require() should be the one that sets
the global (if it must) and return the module (I prefer this) into the
caller's environment.

Now, I managed to work around this in 5.1 using the following code
(summary follows it):

do
        local _realG = _G;
        local _real_require = require;
        function require(...)
                local curr_env = getfenv(2);
                local curr_env_mt = getmetatable(curr_env);
                local _realG_mt = getmetatable(_realG);
                if curr_env_mt and curr_env_mt.__index and not
curr_env_mt.__newindex and _realG_mt then
                        local old_newindex
                        old_newindex, _realG_mt.__newindex =
_realG_mt.__newindex, curr_env;
                        local ret = _real_require(...);
                        _realG_mt.__newindex = old_newindex;
                        return ret;
                end
                return _real_require(...);
        end
end

Some fiddling is required to preserve existing metatables on
environments, but in short this version of require() while running
sets __newindex on the main _G to point to the caller's _G, and this
is where loaded modules will be injected. Everything works as expected
in sandboxes. It restores the old metatable (if any) after the real
require() is done with its potential global stomping.

And now this is an issue for me... in 5.2 without a getfenv() this
code will depend on the debug library, which upsets me. What am I to
do? Live with it?

Matthew