卢阿:这会引起一个断层吗

Lua: Can this cause a segfault

本文关键字:一个 卢阿      更新时间:2023-10-16

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

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

而segfault已经不再发生了。这可能是问题所在吗?

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

你可以在Lua手册中看到这些东西:对于每个函数,它都在描述中拼写出来,也用灰色表示,在函数原型旁边的括号中。例如,lua_getglobal具有[-0,+1,e],这意味着它不会弹出任何元素,并且(总是)推送一个元素(e意味着它可能会导致错误)。

根据www.lua.org/manual/5.2/manual.html#4.2,您有责任保持堆栈清洁,因为lua不会执行任何检查。我会假设segfault是没有保持堆栈干净的合理结果(新值被推到实际堆栈空间之外的内存位置,偶尔也会推到进程虚拟内存之外)。

由于您没有调用lua_call来从堆栈中删除非函数,因此这将无限期地增加堆栈。

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

不过,我对lua_call引用的理解是,即使nresults为0,错误代码也可以留在堆栈上。编辑:我也检查过这种行为,它和我想象的完全一样。

在这种情况下,在开始时调用lua_gettiop,在结束时调用lua_settop在任何情况下都可以工作,并保持堆栈平衡。