2

I am working on a lua script interrupt project, I want to use std::Stack and lua coroutine to save the context. But when I set stacksize to more than 38, it randomly crashes in lua_resume and lua_close. test.lua:

local stacksize = 40 --When changing stacksize less than 30, it runs fine.
function heavy_function(i)
    print("heavy_function start",i)
    if i < stacksize then 
        coroutine.yield(i+1)
    end
    print("heavy_function end",i)
end

main.cpp:

#ifdef __cplusplus
extern "C" {
#endif
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

#ifdef __cplusplus
}
#endif

#include <iostream>
#include <unistd.h>
#include <ctime>
#include <stdio.h>
#include <string>
#include <stack>
using namespace std;

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

    int ret = luaL_dofile(L, "test.lua");
    if (ret != 0)
    {
        // Error loading script. Return.
        printf("luaL_dofile error \n");
        return -1;
    }

    // Add a count hook that will trigger after "count" number instructions
    //lua_sethook(L, LUAHook, LUA_MASKLINE, 0);

    stack<lua_State *> Lstack;
    Lstack.push(lua_newthread(L));
    int init = 1;
    do{
        lua_getglobal(Lstack.top(), "heavy_function");
        lua_pushinteger(Lstack.top(),init);
        ret = lua_resume(Lstack.top(),L,1);
        if(ret == LUA_YIELD)
        {
            init = luaL_checkinteger(Lstack.top(),-1);
            Lstack.push(lua_newthread(L));
        }
        else if(ret == 0)
        {
            //lua_close(Lstack.top());
            lua_gc(L,LUA_GCCOLLECT,0);
            cout<<"Memory Usage:"<<lua_gc(L,LUA_GCCOUNT,0)<<endl;
            Lstack.pop();
        }
        else{
            cout<<"error"<<endl;
            return -1;
        }
    }while(Lstack.size()>0);
    //printf("lua script interrupted \n");
    lua_close(L);
    return 0;
}

Compiler option:

g++ -g main.cpp -o test -llua -ldl

I suspect that I made a mistake while calling lua_newthread.So I made a stack check before calling lua_newstate and it became normal.

if(ret == LUA_YIELD)
{
    init = luaL_checkinteger(Lstack.top(),-1);
    Lstack.push(lua_newthread(L));
    cout<<"lua_checkstack(L,10) = "<<lua_checkstack(L,1)<<endl;//Add a line in line 47
}

Wanted to know if I made a mistake in this and how can I make it right?

1 Answers1

2

You are overflowing the Lua stack by continuously generating new Lua threads and leaving its Lua objects on stack.

lua_newstack() not only returns a pointer to lua_State structure, it also leaves a value of type LUA_TTHREAD on a stack in your L state. You should either accommodate the Lua stack accordingly, or manage returned Lua threads in some other way.

Quick and dirty "fix" would be to call lua_checkstack(L, 10); right before your Lstack.push(lua_newthread(L)); line. It allows your code to run as is, but the stack would continuously grow. Instead you should grab the new thread object off the stack and put it in some Lua table until the time comes for it to be deleted.

Vlad
  • 5,450
  • 1
  • 12
  • 19