如何为LUA创建安全的C接口

时间:2011-12-16 02:43:23

标签: c lua swig

我正在研究如何在我的应用程序中集成完整的脚本支持,但是在规划我的C API以使LUA友好时会遇到一些问题。

基本上我有一堆通过init和free创建的结构 这样的功能:

[test.h]

typedef struct
{
char name[ 50 ];
} Test;


Test *TestAdd( char *name );

Test *TestDelete( Test *test );

[test.c]

Test *TestAdd( char *name )
{
Test *test = ( Test * ) calloc( 1, sizeof( Test ) );

strcpy( test->name, name );

return test;
}


Test *TestDelete( Test *test )
{
free( test );
return NULL;
}

我使用swig生成LUA模块,因此我创建了以下接口文件:

[test.i]

%module test
%{

%}

Test *TestAdd( char *name );

Test *TestDelete( Test * test );

如果用户代码如下所示,一切正常:

a = test.TestAdd( "test" )
a = test.TestDelete( a )

if( a != nil ) print( a.name )

但是如果用户代码是这样的:

a = test.TestAdd( "test" )
test.TestDelete( a )

if( a != nil ) print( a.name ) -- Crash the app with bad_access (not just a LuaVM error).

甚至最差:

a = test.TestAdd( "test" )
test.TestDelete( a )
test.TestDelete( a )
-- Another way of making crash my app completely!

有没有办法可以在C中创建一组API来避免这种问题,并允许用户以安全的方式安全地添加/删除和访问属性,不会产生“错误访问”错误并使整个程序崩溃,最好的是LUAVM只返回一个错误并继续执行。

我一直在搜索并尝试使用不同的方法来处理我的C API以避免此问题,但失败了......

任何人都可以帮助我,或者给我一些关于这个方向的指示。

提前致谢,

1 个答案:

答案 0 :(得分:5)

有一种方法可以做到这一点:停止将C风格的接口直接导出到Lua。 C不是Lua,你永远不应该让Lua程序像C程序那样行事。

除非没有办法避免它,否则Lua代码永远不必释放任何东西。如果Lua代码明确地创建了某些东西,那么Lua代码应该在其生命周期内具有治理。这意味着你使用垃圾收集来删除内存:当Lua GC完成它时,你使用metamethod来释放你使用的任何调用指针。

通常,您可以通过以下两种方式之一为Lua指定一个对象:Lua 拥有该指针,或者该指针指向一个比lua_State本身更长的对象(因此将始终可用于Lua脚本)。在某些情况下,你可以向Lua提供一些它可以引用的临时对象,但是应该尽可能避免这些。

您需要做的是use the %newobject directive告诉SWIG TestAdd返回需要删除的指针。然后,您需要将Test对象与TestDelete关联为删除者using %newfree typemap。这样可以将Test的所有权从C转移到Lua。此时,C应该从不手动删除它。让Lua和SWIG完成他们的工作。

因此,TestDelete不应直接暴露给Lua。当GC检测到没有人再引用Test实例时,将隐式调用它。