lua-users home
lua-l archive

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


Thanks for the highlight Peter. Being curious on why "_G" was LOADED, I did this small experiment:

======================== test2.lua
local print = print
local require = require
local req = require"debug".getregistry()
print(req._LOADED._G, _ENV, _ENV._G, _G)
--- table: 0x100100610 table: 0x100100610 table: 0x100100610 table: 0x100100610
_ENV = {}
print(req._LOADED._G, _ENV, _ENV._G, _G)
--- table: 0x100100610 table: 0x100100400 nil nil
_G = require "_G"
print(req._LOADED._G, _ENV, _ENV._G, _G)
--- table: 0x100100610 table: 0x100100610 table: 0x100100610 table: 0x100100610
========================

Incredible... Why would one want to require "_G" ? This also pretty much breaks encapsulation unless you take care to remove _G from _LOADED or remove "require"...

This is mind boggling... I also experiment with requiring other chunks and seeing what _ENV they get:

======================== test3.lua
local req = require "debug".getregistry()
foo = "foo"
print(_ENV, foo)
--- table: 0x100100610 foo
_ENV = {print=print, require=require}
req._LOADED._G = {}
require "baz"
--- table: 0x100100610 foo

This means that the required script gets the original global _ENV even though _LOADED._G has been changed. It can also read the first "foo".

It seems that removing _LOADED._G is not enough to purge "foo"...

Gaspard
On Mon, Jun 27, 2011 at 1:41 PM, Peter Cawley <lua@corsix.org> wrote:
On Mon, Jun 27, 2011 at 11:26 AM, Gaspard Bucher <gaspard@teti.ch> wrote:
>
>
> On Mon, Jun 27, 2011 at 11:29 AM, Jerome Vuarand <jerome.vuarand@gmail.com>
> wrote:
>>
>> 2011/6/27 steve donovan <steve.j.donovan@gmail.com>:
>> > On Mon, Jun 27, 2011 at 11:08 AM, Gaspard Bucher <gaspard@teti.ch>
>> > wrote:
>> >> collectgarbage() ---- does not collect old "foo". Why ? Where is it
>> >> stored ?
>> >> print('end') -- the garbage collection after 'end' removes old "foo".
>> >
>> > It's still there, as a global of the original environment.
>>
>> But the original environment is unreachable (except by the gc_mt.__gc
>> function itself), and it should be collected.
>>
>
> Yes, this was my concern: I thought the original _ENV was unreachable but it
> is not: since "foo" is not garbage collected, it must be reachable from
> somewhere (which means the original _ENV is also reachable). Therefore, the
> question is from where is old _ENV reachable and why ?
> Gaspard

Doing the following before clearing _ENV will do the trick:

do
 local reg = require"debug".getregistry()
 reg._LOADED._G = nil
 reg[2] = {tostring = tostring} -- for print()
end