When computing whether Lua should return from gen-major to gen-minor,
the difference between the total memory and the previous total memory
can be negative, which can result in that negative value being
left-shifted (UB).
With test option HARDMEMTESTS defined, luaC_condGC was calling pre and
pos twice. That made macro checkGC set the stack top before the GC
step and then again before the full collection, but the previous step
could invalidate the pointer used to set top.
A close instruction is still inside the scope of the variables it is
closing. The extra close in a repeat-until (to close variables before
repeating the loop) was being coded outside that scope.
The union may have alignment requirements stricter than some of its
members. Some checking tools (e.g., gcc with options -fsanitize) can
then complain that the result of a cast from pointer to member to
pointer to the union is misaligned.
In 'luaV_finishset', there is an update on a table that is a field on
another table. If the first table is the same as the one with the field
(e.g., after 't.__newindex = t'), the update can change the value on
that field (e.g., there may be a collision and the field is moved, or
the field being updated is '__newindex' itself). After that, the
barrier is called with the table stored in that field, which is not
the correct table anymore.
- 'luaP_isOT' is only used for tests, so it is defined as a macro to avoid
wasting space with an unused function.
- 'luaP_isIT' must include OP_VARARGPREP.
'lua_load' does not preserve the stack through the calls to the
reader function, as it should. Immediately after the first call (to
detect whether chunk is binary) it adds stuff, and it also adds a new
table when starting the compilation of each new function.
Before calling a finalizer, Lua not only checks stack limits, but
actually ensures that a minimum number of slots are already allocated
for the call. (If it cannot ensure that, it postpones the finalizer.)
That avoids finalizers not running due to memory errors that the
programmer cannot control.
The computation of a new debt could overflow when we give a too large
step to 'collectgarbage"step"' and the current debt was already
negative. This is only an issue if your platform cares for it or if you
compile Lua with an option like '-fsanitize=undefined'.
If the stack does not have some minimum available space, the GC defers
calling a finalizer until the next cycle. That avoids errors while
running a finalizer that the programmer cannot control.