Skip to content

Instantly share code, notes, and snippets.

@szakharchenko
Created April 19, 2018 08:54
Show Gist options
  • Save szakharchenko/8f6559f08f2661ad0c3cb38792860235 to your computer and use it in GitHub Desktop.
Save szakharchenko/8f6559f08f2661ad0c3cb38792860235 to your computer and use it in GitHub Desktop.
Obtaining a reference to an already finalized object from Lua
-- Demonstration of how a reference to an already finalized object
-- can be constructed entirely from Lua. Compatible with Lua 5.1..5.3.
-- Helper to create a value calling a specific callback when it is GCd.
local gc_handler
if newproxy then
gc_handler=function (callback)
local ret=newproxy(true)
getmetatable(ret).__gc=callback
return ret
end
else
gc_handler=function(callback)
return setmetatable({},{__gc=callback})
end
end
-- We'll be tracking object states here, with objects represented by
-- their string representation (holds no reference but contains the
-- pointer value, so should be reasonably unique).
local object_states={}
local live=setmetatable({},{__mode="v"})
local idle={}
for i=1,3 do -- third time's a charm
local key,use_fn=next(idle)
if use_fn then
idle[key]=nil
else
key={}
-- This creates the object being attacked. We just set the
-- state for this test. Note that the finalizer doesn't do
-- anything tricky like storing the last reference to the
-- object anywhere.
local obj=gc_handler(function(obj_ref) object_states[tostring(obj_ref)]="dead" end)
object_states[tostring(obj)]="live"
use_fn=function () -- holds obj as upvalue
if object_states[tostring(obj)]~="live" then
error("using object in state "..(object_states[tostring(obj)] or "nonexistent"))
end
end
end
local wrapper={
use_fn=use_fn,
gch=gc_handler(function() idle[key]=use_fn end) -- holds use_fn, which holds obj, as upvalue
}
live[key]=wrapper
wrapper.use_fn()
collectgarbage("collect")
end
--[[
# lua51 x.lua
lua51: x.lua:41: using object in state dead
stack traceback:
[C]: in function 'error'
x.lua:41: in function 'use_fn'
x.lua:50: in main chunk
[C]: ?
# lua52 x.lua
lua52: x.lua:41: using object in state dead
stack traceback:
[C]: in function 'error'
x.lua:41: in function 'use_fn'
x.lua:50: in main chunk
[C]: in ?
# lua53 x.lua
lua53: x.lua:41: using object in state dead
stack traceback:
[C]: in function 'error'
x.lua:41: in field 'use_fn'
x.lua:50: in main chunk
[C]: in ?
# lua51 -v
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
# lua52 -v
Lua 5.2.4 Copyright (C) 1994-2015 Lua.org, PUC-Rio
# lua53 -v
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org, PUC-Rio
# uname -prs
FreeBSD 11.1-RELEASE-p4 amd64
]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment