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

我正在研究如何在我的应用程序中集成完整的脚本支持,但是在计划我的 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 ) -- 引发错误,使应用程序崩溃,而不仅仅是 LuaVM 错误。

或者更糟糕:

a = test.TestAdd( "test" )
test.TestDelete( a )
test.TestDelete( a )
-- 完全让我的应用程序崩溃的另一种方式!

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

我一直在搜索并尝试不同的方法来避免此问题,但失败了...

有人可以帮助我或给我一些指针关于这个方向。

提前致谢,

原文链接 https://stackoverflow.com/questions/8529205

点赞
stackoverflow用户734069
stackoverflow用户734069

有一种方法可以做到这一点:停止直接向 Lua 导出 C 风格的接口。C 不等于 Lua,你永远不应该期望 Lua 程序像 C 程序一样运行。

除非没有办法避免,否则 Lua 代码不应该手动释放任何资源。如果 Lua 代码显式地创建了某些东西,那么 Lua 代码应该对其生命周期有控制权。这意味着你要使用垃圾回收机制来删除内存:当 Lua GC 使用完它后,你可以使用 metamethod 来使用任何调用来释放指针。

通常情况下,有两种方式可以将指针交给 Lua:要么 Lua 拥有 该指针,要么该指针指向的对象将超越 lua_State 本身的生存期(因此将始终可供 Lua 脚本使用)。有时你可能会将一些临时对象交给 Lua 引用,但应尽量避免这种情况。

你需要做的是使用 %newobject 指令来告诉 SWIG, TestAdd 返回一个需要删除的指针。然后,你需要将 Test 对象与 TestDelete 关联起来作为删除器,使用 %newfree typemap。这将正确地将 Test 的所有权从 C 转移到 Lua。此后,C 应该 不要 手动删除它。只要让 Lua 和 SWIG 做他们的工作。

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

2011-12-16 03:03:35