hey @zep, I've found a nasty coroutine(?)/multival bug. I'm on Linux + picotron 0.1.0d.
tl;dr: sometimes select("#",tostr(i))
is 2, possibly triggered by calling coresume() with extra args.
I ran into this initially because add({},3,nil)
is a runtime error now (it used to work in PICO-8, but now it throws bad argument #2 to 'add' (position out of bounds)
). I had some code: add(list,quote(arg))
that was crashing as if quote() was returning a second value for some reason, even though the code for quote() definitely returned just one value. (surrounding it in parens (to only keep the first return value) fixed my bug: add(list,(quote(arg)))
)
Version A of the code is very short, and trips the assert inside spin
maybe 50% of the time? sometimes many runs in a row don't trigger the assert, but sometimes many runs in a row all trigger the assert. (maybe that's just statistics tho). Version B is a bit more complex but always trips the assert instantly for me.
Version A: (short, inconsistent)
Version B: (longer, very consistent)
As noted in Version A, the two coresume-wrapping-functions inside cocreate_spin() act differently -- I've never been able to trip the assert with the "good" version. I've tried versions of this code with no coroutines and haven't been able to trip the assert.
idk what else to say, this bug seems baffling -- sometimes select("#",quote(i))
is 2, despite quote() being a wrapper for tostr()
Fascinating! I was able to simplify the reproduction quite a bit and have it fail every single time (sometimes it takes 100,000+ iterations, sometimes it only takes 650 🤷♂️):
coro = cocreate(function() for i=1,10000000 do -- ceil() could be any function as long as it's called within a co-routine -- and it should ALWAYS return only one value local rets = pack(ceil(i)) if #rets > 1 then assert(false, "\n"..table.concat(rets, "\n")) end end end) -- second param to coresume _sometimes_ causes errors -- remove second param to coresume, then it works assert(coresume(coro, "uh-oh")) |
It looks like any function called within a coroutine could occasionally return the parameter(s) passed to coresume
(try adding more args to the coresume(...)
call - they call get returned from ceil()
)!
Edit: Reproduced in 0.1.0d on MacOS M1.
The equivalent code in lua 5.4.6 on my host machine (MacOS 12.4 M1) doesn't exhibit any errors:
coro = coroutine.create(function() for i = 1, 10000000 do -- ceil() could be any function as long as it's called within a co-routine local rets = table.pack(math.ceil(i)) if #rets > 1 then assert(false, "\n" .. table.concat(rets, "\n")) end end end) -- never errors assert(coroutine.resume(coro, "uh-oh")) |
great work shrinking this down! I forget if I said that in discord or not -- nice work, your repro code is nice and tiny
I just tried this in pico8, and it has a similar bug: https://www.lexaloffle.com/bbs/?tid=142550
I also tried your last snippet ("The equivalent code in lua 5.4.6...") on my machine (linux 6.6.30-2-MANJARO x86_64 / Lua 5.4.6) and it does not error, as expected
[Please log in to post a comment]