I think I've run into a Python userdata/reference issue with the new lua 5.5 backend.
This reproduces for me with lupa 2.8:
import lupa.lua54 as lua54
import lupa.lua55 as lua55
class Entity:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"Entity({self.name})"
def test(lua):
runtime = lua.LuaRuntime()
echo = runtime.eval("function(entity, event) return entity end")
entities = [Entity("A"), Entity("B"), Entity("C")]
for i in range(10000):
expected = entities[i % 3]
actual = echo(expected, runtime.table(name="update"))
if actual is not expected:
print("failed at", i)
print("expected:", expected, id(expected))
print("actual: ", actual, id(actual))
return
print("passed")
print("lua54:")
test(lua54)
print("lua55:")
test(lua55)
For me:
lua54:
passed
lua55:
failed at 51
expected: Entity(A)
actual: Entity(C)
The exact failing call can move around in a larger repro, but lua55 consistently ends up substituting another live Python object for the one that was passed in. lua54 survives 10,000 calls.
I originally found this in a Lua -> Python -> Lua callback path where an entity argument eventually became another Python object associated with that entity (a dict). I reduced it down to the above, which doesn't need the callback/re-entry at all.
Possibly related to #293, although that one reproduces on 5.2/5.3 and not 5.4+, while this one seems specific to 5.5 for me.
Environment:
Lupa 2.8
Python 3.10.12
Ubuntu 22.04 x86_64
Linux 6.8.0-136-generic #136~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Jul 3 16:29:11 UTC 2026
I also checked the installed extensions: lupa.lua54 and lupa.lua55 are separate binaries and neither dynamically links a system liblua, so this doesn't look like a 5.4/5.5 shared-library ABI mixup.
For now I've fixed it by using the 5.4 backend.
I think I've run into a Python userdata/reference issue with the new lua 5.5 backend.
This reproduces for me with lupa 2.8:
For me:
The exact failing call can move around in a larger repro, but lua55 consistently ends up substituting another live Python object for the one that was passed in. lua54 survives 10,000 calls.
I originally found this in a Lua -> Python -> Lua callback path where an entity argument eventually became another Python object associated with that entity (a dict). I reduced it down to the above, which doesn't need the callback/re-entry at all.
Possibly related to #293, although that one reproduces on 5.2/5.3 and not 5.4+, while this one seems specific to 5.5 for me.
Environment:
I also checked the installed extensions:
lupa.lua54andlupa.lua55are separate binaries and neither dynamically links a system liblua, so this doesn't look like a 5.4/5.5 shared-library ABI mixup.For now I've fixed it by using the 5.4 backend.