Summary
After requiring a module whose body issues several nested requires and defines many local functions that close over the required value, the local binding ends up with a value that lacks the required module's fields. The result behaves as if package.loaded[modname] was read while still holding the true sentinel that parse_and_execute_module writes before executing the module body.
Discovered while bumping lua to 9344c7cc9835dfa15f1240e6a9de5c9e102b146a (which includes the ? → modname dot-to-slash fix) in tv-labs/platform/sidecar, which ships luassert under priv/lua/.
Repro
From tv-labs/platform/sidecar on dave/sidecar-bump-lua-1.0.0-rc.0 with mix.exs pinned to commit 9344c7cc9835dfa15f1240e6a9de5c9e102b146a:
priv = :code.priv_dir(:sidecar)
paths = "#{priv}/lua/?.lua;#{priv}/lua/?/init.lua"
lua = Lua.new(exclude: [[:require], [:package]])
lua = Lua.set_lua_paths(lua, paths)
Lua.eval!(lua, "require('luassert.assertions'); return 'ok'")
Errors with:
Lua runtime error: Runtime Type Error
at -no-source-:307:
attempt to call a nil value (method 'register' on local 'assert')
luassert/assertions.lua:307 is the first assert:register(...) after local assert = require('luassert.assert') at line 9.
Observations
require('luassert.modifiers') works. Same shape (local assert = require('luassert.assert') then assert:register(...)) but only 19 lines, and the assert:register calls are right after the require — no intermediate local function defs that close over assert.
require('luassert.assertions') fails at line 307.
require('luassert.array') fails at line 66.
require('luassert.spy') fails at line 182.
All three failing modules have the same pattern: local assert = require('luassert.assert') at the top, ~50+ local function definitions in between (whose bodies do assert(...) via the metatable's __call), then the first assert:register(...) is what trips.
At the failing line, assert is non-nil but assert.register is nil. Reference Lua returns the same obj table both times. The value the local ends up holding looks like the true sentinel that parse_and_execute_module writes to package.loaded[modname] before executing the module body — as if the post-execution overwrite at line 724 isn't seen by the outer state.
Related (also fixed in this branch)
- Original blocker:
find_module_file (lib/lua/vm/stdlib.ex:754) didn't convert . to / in modname before substituting into the pattern. Fixed in 9344c7c. This new bug is separate.
Sidecar bump tracking
Summary
After requiring a module whose body issues several nested
requires and defines manylocal functions that close over the required value, the local binding ends up with a value that lacks the required module's fields. The result behaves as ifpackage.loaded[modname]was read while still holding thetruesentinel thatparse_and_execute_modulewrites before executing the module body.Discovered while bumping
luato9344c7cc9835dfa15f1240e6a9de5c9e102b146a(which includes the?→ modname dot-to-slash fix) intv-labs/platform/sidecar, which ships luassert underpriv/lua/.Repro
From
tv-labs/platform/sidecarondave/sidecar-bump-lua-1.0.0-rc.0withmix.exspinned to commit9344c7cc9835dfa15f1240e6a9de5c9e102b146a:Errors with:
luassert/assertions.lua:307is the firstassert:register(...)afterlocal assert = require('luassert.assert')at line 9.Observations
require('luassert.modifiers')works. Same shape (local assert = require('luassert.assert')thenassert:register(...)) but only 19 lines, and theassert:registercalls are right after the require — no intermediatelocal functiondefs that close overassert.require('luassert.assertions')fails at line 307.require('luassert.array')fails at line 66.require('luassert.spy')fails at line 182.All three failing modules have the same pattern:
local assert = require('luassert.assert')at the top, ~50+local functiondefinitions in between (whose bodies doassert(...)via the metatable's__call), then the firstassert:register(...)is what trips.At the failing line,
assertis non-nil butassert.registeris nil. Reference Lua returns the same obj table both times. The value the local ends up holding looks like thetruesentinel thatparse_and_execute_modulewrites topackage.loaded[modname]before executing the module body — as if the post-execution overwrite at line 724 isn't seen by the outer state.Related (also fixed in this branch)
find_module_file(lib/lua/vm/stdlib.ex:754) didn't convert.to/inmodnamebefore substituting into the pattern. Fixed in 9344c7c. This new bug is separate.Sidecar bump tracking
tv-labs/platformbranch:dave/sidecar-bump-lua-1.0.0-rc.0