最近项目c应用程序嵌入lua脚本,在lua中用到了第三方库luasocket,程序启动报错:

Undefined symbol "lua_insert"

问题困扰我2天直到找到一片文章

链接lua的正确方式

这几天,我们遇到一个问题:在xy2.5引擎里面,使用posix库或者socket库时,主

程序会crash。,改变代码的顺序或加入 print代码,主程序又可能不会再crash了。检

查产生的core文件,发现内存已经被破坏掉了,无法从中得知调用堆栈的信息。经过后

来用多种手段检查(在另一篇文章中介绍),终于发现问题所在:在垃圾回收过程中,

free了dummynode_,而dummynode_实际上是一个静态变量,不是通过malloc分配的。

进一步分析,才发现是由于链接参数不正确导致的。

正确的编译和链接方式是:

1. lua解释器

按官方的做法,lua解释器被编译成静态链接库。其Makefile也未写明编译为动态链接

库的方式。因此,假定大家都用静态链接的方式使用lua。

2. 第三方库

如posix和socket,以socket库为例,连接生成socket.so时的指令为:

ld -o socket.so $(SOCKET_OBJS)

注意:这里并没有写成

ld -o socket.so $(SOCKET_OBJS) -llua

即没有把lua解释器也链接进来,如果加了-llua,就会在socket.so中,有一份自己的

dummynode_。

3. 应用程序

应用程序内嵌lua解释器,又会在lua脚本中使用第三方库,所以,首先要-llua,将lua

链接进应用程序,同时又要用-Wl,-E, 将lua中的符号导出,让第三方库能访问这些符

号。

/usr/local/bin/g++ -g -O0 -Wl,-E -o run -L/usr/local/lib

-I/usr/local/include -include

stdlib.h mytest.cpp -llua

-lexecinfo

可能的错误做法:

在编译链接应用程序时,未指明-Wl,-E

/usr/local/bin/g++ -g -O0 -o run -L/usr/local/lib

-I/usr/local/include -include stdlib.h mytest.cpp -llua -lexecinfo

这样会导致在使用socket.so时提示:

Undefined symbol "lua_insert"

于是,就在编译socket.so时,加上-llua。

这样做以后,没有编译链接错误,程序也能够跑起来。但问题被隐藏起来了。

我们来看看创建对象和释放对象时的代码,以发现问题:

a) 创建对象时

lua会给对象的node属性设置初始值:

t->node = cast(Node*, dummynode)

b) 释放对象时

会判断是否应该释放节点:

if (t->node != &dummynode_)

lua_free(t->node)

按照上面错误的链接方式,socket.so中有一份dummynode_,在应用程序中也有一份

dummynode_。设置

t->node时,可能使用的是应用程序内的dummynode_的地址;而释放

阶段比较地址时,使用的是socket.so中的 dummynode_的地址,这样,就调用了free释

放了不是malloc分配出来的地址空间。 于是内存空间被破坏,程序crash。

--

邹光先

-Wl,-E和-llua这两个编译选项以后不能忘记了