C&Lua防止不良访问或双重释放

C & Lua prevent bad access or double free

本文关键字:释放 访问 不良 Lua      更新时间:2023-10-16

我成功地将Lua集成到我的C语言应用程序中,为用户提供了脚本访问权限。现在我的问题是:如何防止双重自由访问或不良访问违规?

我已经为每个结构体实现了Init和Free函数,例如:

  • structaInit
  • structaFree

我还跟踪每次一个结构指针链接到另一个结构指针,增加所有结构中存在的引用计数。

但是用户可以在Lua中做这样的事情:

a = structaInit();
b = structbInit();
structbSetA( b, a ); -- This add ++a.reference
a.reference = 0; 
a = structaFree( a ); -- If a->reference == 0 then I free
-- Then struct b->a is still a valid pointer but that have been free.

有什么方法可以防止这种情况发生吗?

这个问题与所有权有关。让我们以Lua脚本为例:

a = structaInit();
b = structbInit();

这会创建Lua现在拥有的C对象。Lua将决定何时为这些对象释放内存。

那么这个呢?

structbSetA( b, a ); -- This add ++a.reference

首先,structbSetA应该是b的成员,通过一个元表(所以它成为b:setA(a))。但更重要的是,谁拥有a ?

Lua。因为它必须拥有A;Lua不能完全放弃仍然在Lua内存中的对象的所有权。这意味着你的内部引用计数最终是没有意义的;唯一重要的是Lua的。

如果您打算将a的值存储在b中,这样只要b仍然存在,b就可以引用a,那么您需要通过Lua方法创建这种关系。你不能只是把C指针指向b中的a,然后期望一切顺利。

最简单的方法是,对于您创建的每个对象,在Lua注册表中创建一个表,该表存储Lua对象所具有的任何引用。当对象被销毁时,您进入Lua注册表并从中删除该表,从而导致销毁任何引用的Lua对象。显然,当稍后调用structbSetA修改该值时,您需要更改该值。


还有,为什么你要把这个暴露给Lua:

a.reference = 0;

这是一个糟糕的API。Lua代码不应该处理引用计数。您也不应该向Lua公开显式的"free"方法,除非您需要Lua在完成使用后立即释放某些资源。对于操作系统类型的资源,如文件句柄等,应该只需要。对于普通对象,让垃圾回收器完成它的工作。

不要将c语言暴露给Lua代码。让Lua代码看起来像Lua代码

在这种情况下,它归结为编程实践,你真的不想阻止它,你实际上想让它出错,因为使用你的脚本的人知道他们做错了什么(同样的方式在obj-c它崩溃当你过度释放)。如果你不想发生这种情况,你可能不得不跟踪堆上所有指向链表或其他结构体的活动指针,但我认为这是不值得的。