After getting the main state from the Lua registry, this function had
two Lua thread values on its Lua stack but we only removed one which
lead to a value being left on the stack.
Why did this not blow up before? Because undefined behavior.
The only place where this was called was when creating a Lua reference
value where luaL_ref is called in the same expression (see
UniqueLuaReference::create). The evaluation order of the parameters for
the make_shared call is not defined by the standard and for some reason
all major compilers (except clang) choose to execute the luaL_ref call
before the getMainThread call.
For those compilers, everything is fine. We have some extra values on
the Lua stack but that gets cleaned up after the API function finishes.
However, clang first evaluates the getMainThread which leaves an extra
Lua thread on the Lua stack. The luaL_ref call then references this
thread value instead of the intended value. In the concrete case, this
meant that LuaFunction saw that the reference points to a thread and
rightfully threw an exception.
This fixes#5904.
This adds a Lua API for representing asynchronous operations and running
coroutines based on those operations comfortably. This is very similar
to features other languages have introduced such as C# or JavaScript. In
fact, the whole "promise" thing is derived from how JavaScript
represents these operations.
This is the initial and very basic system for supporting async
coroutines in Lua. There is no native support for running these
operations at specific points (they run whenever the awaited promise
resolved) or making sure they do not leak through different game states.
This adds a utility library for handling all the nasty lua referencing
stuff. It also provides functions for convienent usage of lua objects
such as tables and functions which allows to use them directly from C++
code without using the ugly Lua C-API.