top | item 39522553

(no title)

corsix | 2 years ago

Unfortunately things aren't so simple, as when doing JIT compilation, LuaJIT _will_ try to shorten the lifetimes of local variables. Using the latest available version of LuaJIT (https://github.com/LuaJIT/LuaJIT/commit/0d313b243194a0b8d239...), the following reliably fails for me:

  local ffi = require"ffi"
  local function collect_lots()
    for i = 1, 20 do collectgarbage() end
  end
  local function f(s)
    local blob = ffi.new"int[2]"
    local interior = blob + 1
    interior[0] = 13 -- should become the return value
    s:gsub(".", collect_lots)
    return interior[0] -- kept alive by blob?
  end
  for i = 1, 60 do
    local str = ("x"):rep(i - 59)
    assert(f(str) == 13) -- can fail!!
  end

discuss

order

epcoa|2 years ago

Well that is from 3 weeks ago. If that remains then it’s a bug or the documentation is wrong. What are the rules for keeping a GC object alive? What earthly useful meaning can “Lua stack” have in the FFI GC documentation if not to local bindings since that is the only user visible exposure of it in the language.

From the LuaJIT docs: So e.g. if you assign a cdata array to a pointer, you must keep the cdata object holding the array alive as long as the pointer is still in use:

  ffi.cdef[[
  typedef struct { int *a; } foo_t;
  ]]

  local s = ffi.new("foo_t", ffi.new("int[10]")) -- WRONG!

  local a = ffi.new("int[10]") -- OK
  local s = ffi.new("foo_t", a)
  -- Now do something with 's', but keep 'a' alive until you're 
  done.
What on earth does "OK" here mean if not the local variable binding? It's the expectation because this is what it says on the tin.

This then isn’t a discussion about fundamental issues or "impossibilities" with GC, but with poor language implementations not following their own specifications or not having them.

Since LuaJIT does not have an explicit pinning interface the expectation that a local variable binding remains until the end of scope is pretty basic. If your bug case is expected then even the line: interior[0] = 13 is undefined and so would everything after local s in the documentation, ie you can do absolutely nothing with a pointed to cdata until you pin it in a table. Who would want to use that?

matheusmoreira|2 years ago

You're absolutely right. I'm not particularly familiar with LuaJIT so when I read the article I got the impression the LuaJIT GC semantics weren't documented. Looks like the LuaJIT behavior is well defined and the implementation isn't keeping its own promises.