PANIC:调用Lua API时未受保护的错误(未定义的符号:lua_gettop)

我的环境是 Lua-5.4.2 Luasocket-3.0-rc1。 当我直接运行 lua 脚本时,它成功运行。 但是当我通过 C 语言运行它时,它会出现错误。

错误消息为: PANIC:调用Lua API时未受保护的错误(运行脚本时出错:从文件'/usr/local/lib/lua/5.4/socket/core.so' 加载模块'socket.core'出错:未定义的符号:lua_gettop) 已终止(core dumped)

有人知道为什么吗?

lua 脚本代码如下:(test.lua)

#!/usr/local/bin/lua
local socket = require("socket")
print(socket._VERSION)

C 代码如下:(main.c)

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
int main(void)
{
    lua_State *L;
    L = luaL_newstate();
    luaopen_base(L);
    luaL_openlibs(L);

    printf("lua进入\n");
    if (luaL_dofile(L, "test.lua"))
    {
        luaL_error(L, "运行脚本出错:%s", lua_tostring(L, -1));
    }
    printf("lua退出\n");

    while(1) pause();
    lua_close(L);
    return 0;
}
点赞
用户7509065
用户7509065

tl;dr: 在 GCC 中添加 -Wl,-E 参数即可。

我使用以下 Dockerfile 复现了你的问题:

FROM gcc:11.1.0
RUN wget https://www.lua.org/ftp/lua-5.4.2.tar.gz \
 && git clone https://github.com/diegonehab/luasocket.git
RUN tar zxf lua-5.4.2.tar.gz \
 && cd lua-5.4.2 \
 && make linux \
 && make install \
 && cd ../luasocket \
 && git checkout 5b18e475f38fcf28429b1cc4b17baee3b9793a62 \
 && make linux LUAV=5.4 \
 && make install LUAV=5.4
COPY test.lua main.c ./

当我在生成的 Docker 容器中运行 lua test.lua 时,它能够正常工作。但是当我运行 gcc -o test main.c /usr/local/lib/liblua.a -ldl -lm -Wl,-rpath='/usr/local/lib/lua/5.4/socket' && ./test 时,我得到了你得到的相同的 panic 错误。

之所以独立的 Lua 二进制文件可以工作而你的程序不行,是因为前者已经添加了 -E 标志 (-E 标志):

MYLDFLAGS= $(LOCAL) -Wl,-E

[ld 的说明文档] (https://sourceware.org/binutils/docs/ld/Options.html#index-_002dE) 讲到:

如果您使用 dlopen 来加载需要引用程序定义的符号而不是其他动态对象的动态对象,那么在链接程序本身时可能需要使用此选项。

Lua 使用 dlopen 加载 C 模块,在编译时需要调用链接到您的可执行文件中的 Lua 函数,所以很有道理需要使用这个选项。而实际上,当我在 GCC 命令行中添加 -Wl,-E 参数时,程序可以正常工作:

root@077bbb831441:/# gcc -o test main.c /usr/local/lib/liblua.a -ldl -lm -Wl,-rpath='/usr/local/lib/lua/5.4/socket' -Wl,-E && ./test
lua enter
LuaSocket 3.0-rc1
lua exit
2021-06-27 04:16:06