如何执行lua_pushstring并避免内存不足的setjmp异常。

有时候,在分配了一些需要在失败的情况下清理的资源之后,我希望在某些地方使用lua_pushstring。然而,正如文档所暗示的那样,lua_push*函数总是可能出现内存不足的异常。但是,该异常会立即退出我的C范围,不允许我清理任何我可能临时分配的资源,以防出现错误。

示例代码以说明情况:

void* blubb = malloc(20);
...在这里发生其他事情...
lua_pushstring(L, "test"); //如何安全地进行这个调用,以便我仍然可以关心 blubb?
...在这里有更多的事情可能发生...
free(blubb);

有没有一种方法可以事先检查是否会发生这样的异常,然后在安全清理自己的资源后避免推送并触发自己的错误?或者,我可以以某种方式简单地取消setjmp,然后在进行推动后检查一些“魔法变量”,以查看它是否实际上起作用或触发了一个错误?

我考虑过p调用我的自己的函数,但是即使只是将要通过p调用的堆栈上的函数推入堆栈,我也可能会遇到内存不足的情况,不是吗?

为了澄清问题,我专门为与自定义内存分配器结合使用而询问这个问题,这将防止Lua分配过多的内存,因此假定这不是整个系统已经耗尽内存的情况。

原文链接 https://stackoverflow.com/questions/10263585

点赞
stackoverflow用户15996
stackoverflow用户15996

lua_atpanic() 可能是你需要的解决方法之一,具体取决于你需要进行的清理类型。它不会抛出错误。

在你的具体例子中,你也可以创建 blubb 作为 userdata。然后当 Lua 离开栈时,它将自动释放。

2012-04-21 23:01:25
stackoverflow用户734069
stackoverflow用户734069

除非您在创建 Lua 状态时已使用 Lua 注册了用户定义的内存处理程序,否则出现内存不足错误意味着您的整个应用程序已经耗尽了内存。通常情况下,从此状态恢复是不可能的。或者至少,在很多情况下不实际。可能取决于您的应用程序,但可能性不大。

简而言之,如果出现这种情况,你会有更重要的事情需要关注 ;)

唯一应影响您的那些是与应用程序外部相关的清理工作。如果您需要释放一些进程全局内存或设置一些状态,则需要清理工作。如果您正在进行进程间通信并且需要通过内存映射文件进行通信。或者类似的事情。

否则,最好只是杀死您的进程。


您可以将 Lua 构建为 C++ 库。这样做时,错误会变成实际的异常,您可以捕获它们或只使用 RAII 对象来处理它们。

如果您被困在 C 中...嗯,您没什么可做的。

我有一个特别感兴趣的自定义分配器,它将较早地分配内存,以避免 Lua 消耗太多内存。

那么你应该以另一种方式处理它。发出内存不足错误信号基本上意味着“我要让 Lua 立即终止”。

停止 Lua 占用内存的方法是定期检查 Lua 状态的内存,如果它使用过多,则进行垃圾回收。如果那并没有释放足够的内存,那么您应该手动终止 Lua 状态,但仅在安全的情况下才能这样操作。

2012-04-21 23:12:08
stackoverflow用户1204141
stackoverflow用户1204141

我最近又开始使用 Lua 沙盒,现在我认为我之前接受的答案是一个坏主意。我仔细考虑了一下:

为什么周期性检查是不够的

如果你考虑到一个单独的巨大表格可以用一个 VM 指令吃掉你很多内存,关于这一点你只有在它发生之后才会知道,你只有在安全时才终止 Lua,这似乎是一个坏主意 - 在这种情况下,你的程序可能已经因此死掉,这时你确实有更大的问题,如果你及时停止了分配,完全可以避免这些问题。

由于 Lua 已经内置了很好的内存异常处理,因此我只想使用它,因为这允许我做最少的必要事情(防止脚本分配更多东西,同时可能允许其恢复),而不会破坏我的 C 代码。

因此,我目前的 Lua 沙盒内存限制计划是:

-使用定制的分配器,返回带有限制的 NULL。

-设计所有 C 函数以能够在无异常泄漏或其他故障的情况下处理此问题。

但如何安全地设计 C 函数?

如何做到这一点,因为 lua_pushstring 等函数总是可以在未知错误的情况下 setjmp,我不知道这是否会提前发生?(这是我的原始问题)

我认为我找到了一个可行的方法:

我添加了一个注册指针的功能,当我分配它们时进行注册,当我完成它们时进行注销。这意味着如果 Lua 突然将我从我的 C 代码中的 setjmp 中调出而没有让我有机会清理,我有一个全局列表,我需要清理这个混乱,等我重新掌控时。

那丑陋不?

是的,这很丑陋。但是,它很可能会起作用,并且与“周期性检查”不同,它实际上允许我拥有真正的硬限制,并且避免应用程序本身因为攻击太过激进而遇到麻烦。

2014-09-08 02:02:42