Search code examples
luacontinuationsc-api

lua_resume has segmentation faults


I have the follwing code, trying to understand C-Api , lua_resume, continuations and different cases, just for expirements as doc mentions. I am currently in lua 5.4 on an ubuntu desktop. I have the following code:

// Attempt to yield C-Function, into protected mode. - Continuation Function -
static int finishpcall (lua_State *L, int status, intptr_t ctx) {
(void)ctx; // unused parameter
status = (status != LUA_OK && status != LUA_YIELD);
lua_pushboolean(L, (status == 0)); // status
lua_insert(L, 1); // status is first result

printf("%s, %d\n", "From lua", lua_gettop(L)); // it is lua's stack frame = 1
lua_getglobal(L, "co");


lua_resume(lua_tothread(L, 2), NULL, 0, 0);
lua_resume(lua_tothread(L, lua_gettop(L)), NULL, 0, 0);
return lua_gettop(L); // return status + all results
}

static int luaB_pcall (lua_State *L) {
int status;
luaL_checkany(L, 1);
status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, finishpcall);
return finishpcall(L, status, 0);
}

int main(void) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);

// Register luaB_pcall as a Lua function
lua_register(L, "pcall", luaB_pcall);

const char *str = "function test() \
                        local co = coroutine.create(function() print('me') \
                        coroutine.yield() \
                        print('me me') \
                        end) \ 
                        return co \
                   end \
                   pcall(test)";

int res = luaL_dostring(L, str);
if (res != LUA_OK) {
    printf("Error running Lua code: %s\n", lua_tostring(L, -1));
    lua_close(L);
    return 1;
}  

printf("%s, %d\n", "From C-Function", lua_gettop(L)); //it is C's stack frame = 0

lua_close(L);
return 0;
}

Can anyone suggest me why i get segmentaition fault on lua_resume in finishpcall() , although firstly i get From lua, 2 me as results.


Solution

    1. Read the manual carefully, then you'll notice the type of lua_resume's last argument is int*, it's an output argument.

      int lua_resume (lua_State *L, lua_State *from, int nargs, int *nresults);
      

      Although in your example, it is 0, in general, you need to handle them.

      lua_State* co = lua_tothread(L, 2);
      int nresults;
      status = lua_resume(co, NULL, 0, &nresults);
      lua_pop(co, nresults); //handle the results by removing them
      
    2. You'd better use the co variable above for your 2nd lua_resume call too, because you put the global co (which doesn't exist) on the top of the stack.