我成功地将 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
就可以引用a
,那么只要 b
还活着,那么您就需要通过 Lua 方法来创建这种关系。您不能只是将 C 指针指向 b
中的 a
并期望一切顺利。
最简单的方法是,对于您创建的每个对象,在 Lua 注册表中创建一个表,用于存储 Lua 对象的任何引用。当一个对象被销毁时,您进入 Lua 注册表并从中删除该表,从而导致任何引用的 Lua 对象被销毁。显然,当以后调用 structbSetA
修改此值时,您将需要更改它。
另外,你为什么要把它暴露给 Lua:
a.reference = 0;
那是一个糟糕的 API。 Lua 代码应该永远 必须处理引用计数。你也不应该向 Lua 公开一个显式的“释放”方法,除非你需要 Lua 在使用完某些资源后立即释放它。这应该只有对于操作系统类型的资源(如 FILE 句柄等)是必需的。对于常规对象,让垃圾收集器完成它的工作。
不要将 C 语言暴露给 Lua 代码。让 Lua 代码看起来像 Lua 代码。
关于c++ - C & Lua 防止bad access or double free,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6658135/