Lua: 这可能导致 segfault 吗?

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

void Call(std::string func){
    lua_getglobal(L, func.c_str()); //这是GDB在回溯中提到的行
    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));

自那以后,段错误就没有再出现了。这可能是问题吗?

点赞
用户4003853
用户4003853

根据 www.lua.org/manual/5.2/manual.html#4.2,你需要负责保持栈的清洁,因为 Lua 不会执行任何检查。我会 假设 如果不保持栈的清洁(将新值推送到实际栈空间之外的内存位置,恰好也在你的进程虚拟内存范围之外)可能导致段错误。

由于你没有调用 lua_pcall 来从栈中移除非函数,这会无限增加栈的大小。

你的解决方案应该是有效的,除非被调用的函数在栈上留下了某些东西。由于你将 nresults 设置为 0,Lua 不会在栈上留下任何结果。

然而,我理解 lua_pcall 参考文献是即使 nresults 为 0,错误代码仍然可能留在栈上。编辑:我也检查了那个行为,它正是我假设的那样。

在这种情况下,在开头调用 lua_gettop 并在结尾处调用 lua_settop 将始终有效,并保持你的栈平衡。

2014-09-03 14:35:04
用户2128694
用户2128694

使用 lua_gettop(L) 作为 lua_pop 的参数将清除整个 Lua API 栈(相当于lua_settop(0)),这可能不是您想要的。但是,确实存在您的问题,即 lua_getglobal 总是会推送一些内容;如果给定名称的全局变量不存在,则它将压入 nil,就像等效的 Lua 表达式一样。但是,lua_pcall 会弹出函数和所有参数(如果有的话;在您的情况下,您指定了零个),因此如果函数存在,则不会出现问题。您应该做的是在外部 ifelse 子句中添加 lua_pop(L, 1)。这样,您的函数将始终保持 _平衡_(即使栈与之前相同)。

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

2014-09-03 14:38:11