c++luacoroutinelua-c++-connection

simple Lua corotine test crashed at first run


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?


Solution

  • 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