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

如何执行lua_pushstring并避免内存不足的setjmp异常,lua,out-of-memory,setjmp,Lua,Out Of Memory,Setjmp,有时,在分配了一些资源之后,我想在某些地方使用lua_pushstring,在出现故障时需要清理这些资源。然而,正如文档所暗示的,lua_push*函数总是会出现内存不足异常。但那个异常瞬间退出了我的C作用域,不允许我清理我可能临时分配的、在发生错误时必须释放的任何内容 用于说明这种情况的示例代码: void* blubb = malloc(20); ...some other things happening here... lua_pushstring(L, "test"); //how t

有时,在分配了一些资源之后,我想在某些地方使用lua_pushstring,在出现故障时需要清理这些资源。然而,正如文档所暗示的,lua_push*函数总是会出现内存不足异常。但那个异常瞬间退出了我的C作用域,不允许我清理我可能临时分配的、在发生错误时必须释放的任何内容

用于说明这种情况的示例代码:

void* blubb = malloc(20);
...some other things happening here...
lua_pushstring(L, "test"); //how to do this call safely so I can still take care of blubb?
...possibly more things going on here...
free(blubb);
是否有一种方法可以事先检查是否会发生这种异常,然后在安全清理自己的资源后避免推送和执行自己的错误触发?或者我可以简单地停用setjmp,然后在推送之后检查一些“神奇变量”,看看它是否真的工作或触发了错误

我考虑过用pcall调用我自己的函数,但即使只是将我想通过pcall安全调用的函数推到堆栈上,也可能导致内存不足,不是吗

为了解决这个问题,我特别要求将其与自定义内存分配器结合使用,以防止Lua分配过多内存,因此假设这不是整个系统内存不足的情况。

可能是一种解决方案,具体取决于您需要执行的清理类型。它永远不会出错


在您的特定示例中,您还可以将blubb创建为一个。然后Lua将在它离开堆栈时自动释放它。

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

简言之,一旦出现,你就有更大的事情要担心;)

唯一应该影响您的清理是针对应用程序外部的东西。如果您有一些进程全局内存需要释放或设置某些状态。您正在进行进程间通信,但您有一些内存映射文件。或者类似的

否则,最好干脆终止进程


<>你可以把Lua构建成C++库。当您这样做时,错误会变成实际的异常,您可以捕获这些异常,也可以仅使用RAII对象来处理这些异常

如果你被卡在C。。。嗯,你能做的不多


我特别感兴趣的是一个自定义分配器,它将更早地耗尽内存,以避免Lua占用太多内存


那你应该用另一种方式来处理。发出内存不足错误的信号基本上就是说,“我希望Lua立即终止。”


阻止Lua占用内存的方法是定期检查Lua状态的内存,如果它使用了太多内存,则对其进行垃圾收集。如果这不能释放足够的内存,那么您应该手动终止Lua状态,但只有在安全的情况下才能终止。

我最近又遇到了一些Lua沙箱,现在我认为我以前接受的答案是个坏主意。我对此作了更多的思考:

为什么定期检查不够

定期检查大内存消耗并终止Lua“只有当它是安全的时候才这样做”,如果你认为一个巨大的表可以用一个VM指令来消耗大量内存,这是一个坏主意,你只会在它发生后发现它,你的程序可能已经濒临死亡,然后你确实会遇到更大的问题,如果你一开始就及时停止分配,你本可以完全避免这些问题

由于Lua已经内置了一个很好的内存不足异常,我只想使用这个异常,因为它允许我在不中断C代码的情况下完成所需的最小工作(防止脚本分配更多内容,同时可能允许脚本恢复)

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

  • 使用返回带限制的NULL的自定义分配器

  • 设计所有C函数,使其能够在不发生内存泄漏或其他损坏的情况下处理此问题

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

如何做到这一点,因为lua_pushstring和其他人总是可以在我不知道是否会提前发生错误的情况下设置JMP?(这本来是我的问题)

我想我找到了一种工作方法:

我添加了一个功能,可以在分配指针时注册指针,以及在处理完指针后注销指针。这意味着,如果Lua在我没有机会清理的情况下突然将JMP的我从我的C代码中删除,那么我就拥有了一个全局列表中的所有东西,我需要在以后重新控制时清理这些混乱

那是丑陋还是什么?


是的,这是一个相当复杂的问题。但是,它很可能会工作,并且与“定期检查”不同,它实际上允许我有一个真正的硬限制,并避免由于攻击而导致应用程序本身出现问题。

使用
lua_pcall
进行本地错误恢复
lua_atpanic
不适用于该级别的错误恢复,仅适用于应用程序级别。一旦Lua状态达到紧急状态,它就不能被重用。Lua_pcall的问题似乎是,我需要首先推动pcalled函数本身,这也可能导致内存不足。所以我需要把所有的。。。或者:P它并没有真正解决它看起来的问题。我特别感兴趣的是一个定制的分配器,它会更早地耗尽内存,以避免Lua占用太多内存。然而,我不愿意这样做,因为内存不足异常会带来一些问题