Lua:这会导致段错误

时间:2014-09-03 14:12:05

标签: c++ lua

我正在开发一个使用Lua编写脚本的程序,有时它会崩溃。有了GDB我认为我发现了问题,但我不知道它是否解决了它,因为段错误只会偶尔发生。所以,旧代码是这样的:

void Call(std::string func){
    lua_getglobal(L, func.c_str()); //This is the line GDB mentioned in a backtrace
    if( lua_isfunction(L,lua_gettop(L)) ) {
        int err = lua_pcall(L, 0, 0,0 );
        if(err != 0){
            std::cout << "Lua error: " << luaL_checkstring(L, -1) << std::endl;
        }
    }
}

问题是,这个函数每秒会被调用几次,但它需要调用的函数并不总是被定义,所以我认为堆栈会溢出。我添加了以下行:

lua_pop(L,lua_gettop(L));

并且不再发生段错误了。这可能是问题吗?

2 个答案:

答案 0 :(得分:5)

使用lua_gettop(L)作为lua_pop的参数将清除整个Lua API堆栈(它等同于lua_settop(0)),这可能不是您想要的。但实际上你的问题是lua_getglobal总是推动某些东西;如果不存在具有给定名称的全局,则它会推送nil,就像等效的Lua表达式一样。但是,lua_pcall会弹出函数和所有参数(如果有的话;在您的情况下指定为零),因此如果函数存在,您将不会遇到问题。您应该做的是将lua_pop(L, 1)添加到外部else的{​​{1}}子句中。这样,您的函数将始终平衡(即保持堆栈不变)。

您可以在Lua manual中看到这些内容:对于每个函数,它都在说明中拼写出来,并在函数原型旁边的括号中以灰色显示。例如,lua_getglobal有[-0,+ 1,e]意味着它不会弹出任何元素,并且(总是)推送一个元素(并且e意味着它可能导致错误)。

答案 1 :(得分:1)

根据www.lua.org/manual/5.2/manual.html#4.2,您负责保持堆栈清洁,因为Lua不会执行任何检查。我会假设一个段错误是不保持堆栈清洁的合理结果(新值被推送到实际堆栈空间之外的内存位置,并且很可能也在进程虚拟内存之外)。

由于你没有调用lua_pcall从堆栈中删除非函数,这将无限期地增加堆栈。

您的解决方案应该可以工作,除非被调用的函数在堆栈上留下了什么。 由于您将nresults设置为0,因此Lua不会在堆栈上留下任何结果。

我对lua_pcall引用的理解是,即使nresults为0,错误代码也可以保留在堆栈中。编辑:我也检查了这个行为,它完全按照我的假设。

在这种情况下,在开头调用lua_gettop,在结尾调用lua_settop,无论如何都可以保持堆栈平衡。