In brief, the test program creates a coroutine at C++ side, launch it with a Lua-side function and resume several times with some logs. It suddenly crashed at the first call to resume
that starts coroutine running, with violated access to invalid heap memory (0xfdfdfd
).
This is the whole code:
#include <juce_core/juce_core.h>
#include <lauxlib.h>
int debug_log( lua_State* lua )
{
int narg = lua_gettop( lua );
juce::StringArray tokens;
for ( int i = 1; i <= narg; i++ )
tokens.add( lua_tostring( lua, i ) );
juce::Logger::writeToLog( tokens.joinIntoString( "" ) );
return 0;
}
const char* lua_code =
"function testfunc(arg1, arg2)\n"
" debug_log( \"before yield: arg1 \", arg1 )\n"
" coroutine.yield(1)\n"
" debug_log( \"after yield: arg2 \", arg2 )\n"
" coroutine.yield(2)\n"
" debug_log( \"finally in testfunc\" )\n"
"end\n";
int main()
{
auto* lua = luaL_newstate();
luaL_openlibs( lua );
lua_pushcfunction( lua, debug_log );
lua_setglobal( lua, "debug_log" );
luaL_dostring( lua, lua_code );
// create a new coroutine
auto* coro = lua_newthread( lua );
// start corotine
int t_testfunc = lua_getglobal( coro, "testfunc" );
if ( t_testfunc != LUA_TFUNCTION )
{
juce::Logger::writeToLog( "failed to get testfunc from coro: type is " + juce::String( t_testfunc ) );
exit( EXIT_FAILURE );
}
lua_pushstring( coro, "arg1" );
lua_pushnumber( coro, 123.456 );
int n_re = 0;
int status = lua_resume( lua, coro, 2, &n_re ); ///< die here
// repeatedly resume until finished
while ( true )
{
juce::Logger::writeToLog( "status: " + juce::String( status ) + " with " + juce::String( n_re ) + " returned values" );
if ( n_re > 0 )
{
juce::Logger::writeToLog( " returned value " + juce::String( lua_tostring( coro, 1 ) ) );
lua_pop( coro, n_re );
}
if ( status == LUA_YIELD )
{
status = lua_resume( lua, coro, 0, &n_re );
}
else if ( status == LUA_OK )
{
juce::Logger::writeToLog( "coroutine ended" );
break;
}
else
{
juce::Logger::writeToLog( "coroutine returned with error: " + juce::String( status ) );
exit( EXIT_FAILURE );
}
}
}
And this is the stack trace:
> coro_call.exe!luaH_getshortstr(Table * t, TString * key) 行 751 C++
coro_call.exe!luaT_gettmbyobj(lua_State * L, const TValue * o, TMS event) 行 83 C++
coro_call.exe!luaD_tryfuncTM(lua_State * L, StackValue * func) 行 391 C++
coro_call.exe!luaD_precall(lua_State * L, StackValue * func, int nresults) 行 559 C++
coro_call.exe!ccall(lua_State * L, StackValue * func, int nResults, int inc) 行 575 C++
coro_call.exe!resume(lua_State * L, void * ud) 行 731 C++
coro_call.exe!luaD_rawrunprotected(lua_State * L, void(*)(lua_State *, void *) f, void * ud) 行 144 C++
coro_call.exe!lua_resume(lua_State * L, lua_State * from, int nargs, int * nresults) 行 788 C++
coro_call.exe!main() 行 44 C++
Is there any misunderstanding to the Lua coroutine C API?
In addition, the Lua official document gives a pretty long part on concepts of k function and lua_pcallk
, but it seems I don't need them anywhere in my test code. Where should I use these stuffs?
You have a mistake in the order of arguments for lua_resume
It should be lua_resume(coro, lua,
instead of lua_resume(lua, coro,
concepts of k function ... Where should I use these stuffs?
There is a good example on using k-functions
https://stackoverflow.com/a/67961038/1847592