【问题标题】:How to pop / clean Lua call stack from C如何从 C 中弹出/清除 Lua 调用堆栈
【发布时间】:2012-11-16 22:40:43
【问题描述】:

我想在从 Lua 调用的 C 函数中弹出/清理 Lua 调用堆栈。这可能吗?

背景:
我希望我的 C 库及其扩展脚本使用相同的测试框架。 (我知道 Lua 存在各种单元测试工具。我不在乎;我想要一份报告)我将 CUnit 包装在 Lua 的薄层中。 CUnit 提供了致命和非致命测试断言的选择。致命断言会立即导致 longjmp 退出测试并返回到框架运行程序。如果我不先清理堆栈,这似乎会对 Lua VM 造成不利影响。

堆栈可能看起来像:

#0. C:   assert_wrapper_fcn(test, fatal)
#1. Lua: assert_fcn(bool)
#2. Lua: test_fcn()
#3. C:   runner(&test_fcn)

我想清理#0 和#3 之间的所有内容。我知道test_fcn()assert_fcn(bool) 的方法签名,仅此而已。

【问题讨论】:

  • "如果我不先清理堆栈,这似乎会对 Lua VM 造成不利影响。" 它会更糟事情远不止这些。调用堆栈是您最不关心的问题。跳出 Lua 解释器(过去 Lua 自己的 setjmp's)可能会破坏 Lua 中的几乎所有内容。
  • 是的,这也是一个问题。我几乎不知道 Lua 的错误处理系统是如何工作的。真的,我应该用重置解释器的状态来表达这个问题。
  • 你不能。 Lua 不是“longjmp over me”安全的。当应用程序决定在其不知情的情况下半执行一个函数时,Lua 没有处理这种情况的规定。如果你想让你的 Lua 解释器保持理智,那么你需要遵守 Lua 的规则。几乎所有 C 库都是如此。您不能只是随机退出其中一个并期望它对此感到满意。

标签: c lua cunit


【解决方案1】:

清空堆栈非常简单。只需使用 lua_settop 和 0 作为参数。

lua_settop(L, 0);

【讨论】:

    【解决方案2】:

    不确定我是否完全正确地理解了这个问题......但要清除 Lua 的堆栈:

    int stackSize = lua_gettop(L);
    lua_pop(L, stackSize);
    

    【讨论】:

    • 以后从C重新进入Lua就够了吗?如果我明白你在说什么,我可以从 C 中删除堆栈以放弃状态,然后再次安全地使用 lua_call()。这是否也会清除注册表?
    • 看起来@gibbss 表示 C 调用堆栈,而不是 Lua 内部值堆栈。关于注册表问题:不,这不会清除注册表(与堆栈分开,这就是它通过 pseudo-index 引用的原因),但注册表的重点是它是您可以从 C 中编辑并在 Lua-C 转换之间保留的表。
    • 这是对所提问题的准确回答,但显然我提出的方法存在一些严重问题。
    【解决方案3】:

    我的建议是使用 Lua 自己的断言系统,然后在你的运行器中捕获它,然后将错误转发到你的单元测试框架:

    使用 lua_pcall 启动您的 Lua 代码。

    在您的 Lua 代码中,使用标准 assert 命令触发致命错误。

    从您启动 Lua 代码的位置,检查 lua_pcall 的结果,当您得到 != 0 时,触发您的 CUnit 致命断言失败。

    这将避免在 Lua 和 CUnit 之间混合任何 longjmp。

    【讨论】:

    • 这不是一个坏主意——只要稍加工作,错误处理程序仍然可以报告 Lua 行号。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 2012-10-14
    • 2020-04-24
    • 1970-01-01
    • 2021-09-20
    • 2017-03-05
    • 2011-12-24
    相关资源
    最近更新 更多