простой тест на коротину Lua рухнул при первом запуске

Вкратце, тестовая программа создает сопрограмму на стороне C++, запускает ее с помощью функции на стороне Lua и несколько раз возобновляет работу с некоторыми журналами. Внезапно произошел сбой при первом вызове resume, который запускает сопрограмму, с нарушением доступа к недопустимой памяти кучи (0xfdfdfd).

Это весь код:

#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 );
        }
    }
}

А это трассировка стека:

>   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++

Есть ли какое-то недопонимание в отношении C API сопрограммы Lua?

Кроме того, в официальном документе Lua содержится довольно длинная часть о концепциях k function и lua_pcallk, но, похоже, они мне не нужны нигде в моем тестовом коде. Где я должен использовать эти материалы?


person jiandingzhe    schedule 23.06.2021    source источник
comment
В фрагменте lua_code есть опечатки: corotine.yield => coroutine.yield. Я сомневаюсь, что это является источником вашего краха, хотя. Кстати, было бы неплохо использовать необработанную строку С++ 11.   -  person prapin    schedule 23.06.2021
comment
@prapin Исправлена ​​опечатка, хотя причина ошибки здесь не в ней.   -  person jiandingzhe    schedule 23.06.2021


Ответы (1)


У вас ошибка в порядке аргументов для lua_resume
Должно быть lua_resume(coro, lua, вместо lua_resume(lua, coro,

понятия функции k ... Где я должен использовать эти материалы?

Есть хороший пример использования k-функций
https://stackoverflow.com/a/67961038/1847592

person Egor Skriptunoff    schedule 23.06.2021
comment
Я инвертировал порядок аргументов. Теперь сопрограмма начинает работать, но при первом же вызове coroutine.yield() она выдает ошибку внутри функции lua_yieldk, которая фактически реализует операцию yield. - person jiandingzhe; 23.06.2021
comment
Какое сообщение об ошибке выдается? - person Egor Skriptunoff; 23.06.2021
comment
Это не ошибка. Код ошибки — 1, что означает выход сопрограммы. Я должен просто игнорировать это исключение в настройках MSVC. - person jiandingzhe; 24.06.2021
comment
Переключение сопрограмм Lua не вызывает никаких исключений, которые могут быть перехвачены в MSVC. Вы должны начать новый вопрос и описать проблему с вашим кодом. - person Egor Skriptunoff; 24.06.2021
comment
Я уверен, что все в порядке. Если вы скомпилируете исходный код Lua на C++ вместо C, Lua будет использовать throw-try-catch вместо long jump. - person jiandingzhe; 24.06.2021