3

My environment is Lua-5.4.2 Luasocket-3.0-rc1. When I run lua script directly, it work success. When i run it through c language, it tell me error.

Error Msg is : PANIC: unprotected error in call to Lua API (error running script: error loading module 'socket.core' from file '/usr/local/lib/lua/5.4/socket/core.so': undefined symbol: lua_gettop) Aborted(core dumped)

Does anyone know why?

lua script code is:(test.lua)

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

c code is:(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 enter\n");
    if (luaL_dofile(L, "test.lua"))
    {
        luaL_error(L, "error running script: %s", lua_tostring(L, -1));
    }
    printf("lua exit\n");
     
    while(1) pause();
    lua_close(L);
    return 0;
}
Egor Skriptunoff
  • 23,359
  • 2
  • 34
  • 64
Viper
  • 33
  • 2
  • Have you made sure your C program is using the right version of Lua, and that you're compiling it properly (i.e. linking it against Lua properly)? – DarkWiiPlayer Jun 23 '21 at 09:02
  • 1
    C extension modules on Unixes expect the executable to reexport the Lua API. The standard interpreter does this by statically linking the Lua library with the `-Wl,-E` flag. – siffiejoe Jun 23 '21 at 15:01
  • siffiejoe, did I build main.c with -Wl,-E flag? like this: "gcc -o test main.c /usr/local/lib/liblua.a -ldl -lm -Wl,rpath='/usr/local/lib/lua/5.4/socket' -E" ? – Viper Jun 24 '21 at 01:48
  • Hello DarkWiiPlayer, I'm sure c program is using the right version, the version is lua 5.4. – Viper Jun 24 '21 at 05:46
  • As a sanity test, can you make your Lua script do `print(_VERSION)`? – Joseph Sible-Reinstate Monica Jun 26 '21 at 21:59
  • Was all of your Lua code compiled as C, or was some compiled as C++? If the latter, did you remember `extern "C"` everywhere? – Joseph Sible-Reinstate Monica Jun 26 '21 at 22:00
  • @Joseph Sible-Reinstate Monica, yes, I add print(_VERSION) and it shows Lua 5.4. All of my Lua code complied as c. – Viper Jun 27 '21 at 02:42

1 Answers1

0

tl;dr: Pass -Wl,-E to GCC.

I was able to reproduce your problem with this 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 ./

When I run lua test.lua in the resulting Docker container, it works fine. When I run gcc -o test main.c /usr/local/lib/liblua.a -ldl -lm -Wl,-rpath='/usr/local/lib/lua/5.4/socket' && ./test, I get the same panic that you get.

The reason that the standalone Lua binary works and yours doesn't is that the former is linked with -E:

MYLDFLAGS= $(LOCAL) -Wl,-E

ld's documentation for -E says this about it:

If you use dlopen to load a dynamic object which needs to refer back to the symbols defined by the program, rather than some other dynamic object, then you will probably need to use this option when linking the program itself.

Lua uses dlopen to load C modules that you require, and said modules need to call Lua functions, which are linked into your binary, so it makes sense that you need this option. And indeed, when I add -Wl,-E to the GCC command line, then it works fine for me:

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