我成功地将Lua集成到了我的应用程序中,为用户提供了脚本访问权限。现在我的问题是:我如何防止双重免费或不良访问违规?
我已经为每个结构实现了Init和Free函数,例如:
structaInit
structaFree
每次将struct指针链接到另一个时,我也会跟踪,增加我所有结构中的引用计数。
然而,用户总是可以在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.
无论如何我可以防止这种情况发生吗?
答案 0 :(得分:10)
问题与所有权有关。我们来看看你的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's。
如果您打算将a
的值存储在b
中,那么只要b
仍然存在,a
就可以引用b
,那么您需要通过 Lua 方法创建此关系。你不能只将C指针粘贴到a
中的b
并期望一切顺利。
最简单的方法是,对于您创建的每个对象,在Lua注册表中创建一个表,该表存储Lua对象以用于它具有的任何引用。当一个对象被销毁时,你进入Lua注册表并从中删除该表,从而导致任何引用的Lua对象的销毁。显然,稍后调用structbSetA
时,您需要更改此值。
另外,你为什么要把它暴露给Lua:
a.reference = 0;
这是一个糟糕的API。 Lua代码从不必须处理引用计数。你也不应该向Lua公开一个明确的“免费”方法,除非你需要Lua在完成使用后立即释放一些资源。对于像FILE句柄等操作系统类型的资源,仅是必需的。对于常规对象,让垃圾收集器完成它的工作。
不要将C-isms暴露给Lua代码。让Lua代码看起来像Lua代码。
答案 1 :(得分:1)
在这种情况下,它归结为编程练习,你真的不想阻止它,你实际上想让它出错,因为那样使用你的脚本的人知道他们做错了什么(在obj-中的方式相同) c当你过度释放时它会崩溃)。如果您不希望发生这种情况,您可能必须跟踪堆中的所有活动指针到链接列表或某个结构中的结构,但我认为这不值得。