【问题标题】:Lua: Can this cause a segfaultLua:这会导致段错误吗
【发布时间】:2014-09-03 22:44:53
【问题描述】:

我正在开发一个使用 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));

并且段错误不再发生。会不会是这个问题?

【问题讨论】:

    标签: c++ lua


    【解决方案1】:

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

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

    【讨论】:

    • 应该指出的是,在 Lua->C 过渡 lua 确保你有一个新的堆栈,而在 C->lua 过渡 lua 确保堆栈从你可能拥有的任何东西中清除留在上面,因此不需要在这些点上进行平衡(尽管它可能仍然是一个好习惯)。但是,只要您使用 C,就需要堆栈管理(和函数堆栈平衡)。
    【解决方案2】:

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

    由于您不调用 lua_pcall 来从堆栈中删除非函数,这将无限期地增长堆栈。

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

    我对 lua_pcall 引用的理解是,即使 nresults 为 0,错误代码也可以留在堆栈上。编辑:我还检查了该行为,它与我假设的完全一样。

    在这种情况下,在开头调用 lua_gettop 并在结尾调用 lua_settop 在任何情况下都可以正常工作并保持堆栈平衡。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-18
      • 1970-01-01
      • 2011-02-08
      • 2017-08-18
      • 2011-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多