views:

128

answers:

1

Hi.

We're working on multiple computers, executing a program coded in c/c++ and using lua api, and each one of them get crashed with different errors. It's usually either a segmentation fault, whose backtrace leads us to a call made bu liblua, or one that is usually given when trying to call a nil value as if it was a function.

The weird thing is, it works just fine until we reach a number of states (no, we absolutely need multiple states, only one won't be enough). They might refer to the same file -again, which works fine until less than a number of states are opened- or not.

Here's how they're opened, get registered and closed, in case there's something wrong when using multiple states :

lua_State *state=lua_open();
luaL_openlibs(state)
luaL_loadfile(filename.c_str());
...
lua_register(state,"function",function); //dozens of them
...
lua_close(state);

No other state is created until all the registers are done, whether it's closed or not depends on where the state is used.

Here's what I get during the segmentation fault :

#0  0x0013fe79 in ?? () from /usr/lib/liblua5.1.so.0
#1  0x0013325b in lua_pushlstring () from /usr/lib/liblua5.1.so.0
#2  0x001442ba in ?? () from /usr/lib/liblua5.1.so.0
#3  0x00144b61 in luaL_pushresult () from /usr/lib/liblua5.1.so.0
#4  0x00144de5 in luaL_gsub () from /usr/lib/liblua5.1.so.0
#5  0x0014fb52 in ?? () from /usr/lib/liblua5.1.so.0
#6  0x0014ffb7 in ?? () from /usr/lib/liblua5.1.so.0
#7  0x0013839a in ?? () from /usr/lib/liblua5.1.so.0
#8  0x00138834 in ?? () from /usr/lib/liblua5.1.so.0
#9  0x001337a5 in lua_call () from /usr/lib/liblua5.1.so.0
#10 0x0014f3ea in ?? () from /usr/lib/liblua5.1.so.0
#11 0x0013839a in ?? () from /usr/lib/liblua5.1.so.0
#12 0x00138834 in ?? () from /usr/lib/liblua5.1.so.0
#13 0x00133761 in ?? () from /usr/lib/liblua5.1.so.0
#14 0x00137ea3 in ?? () from /usr/lib/liblua5.1.so.0
#15 0x00137f05 in ?? () from /usr/lib/liblua5.1.so.0
#16 0x00133588 in lua_pcall () from /usr/lib/liblua5.1.so.0

And the related code :

lua_getglobal(L,"require");
lua_pushstring(L,"function");
if(!lua_pcall(L,1,0,0))
{
 ...

The string given as the function isn't wrong, it works fine with less than a number of states opened.

When it outputs the "nil value" error, it implies that we didn't use the related lua_register call from inside the program, but it's the same for all other states and again, they work without any problem whatsoever.

I thought it might be due to some memory leak, which I really don't get why since all states are closed.

Is this related to lua api itself (like having a predeterminded number of states might be opened at a time, maybe) ? I know I didn't give too much details, but this is really almost all of the code that is related to lua.

Edit : I forgot including the "require" statement (which I call to push a module), but it was already in the code (thus, not the reason it doesn't work) , sorry about that.

The program is single-threaded. Some objects have lua states as their attributes, hence, multiple states.

The error message indicates it can't find the file it should use... which is actually there and again, can be used without any problem with less states opened.

+1  A: 

The call-site fragment you give doesn't make sense. You have

lua_pushstring(L,"function");
if(!lua_pcall(L,1,0,0)) 
{
 ...

Which doesn't show retrieval of the function named "function", but rather a call to whatever was on top of the stack with its first argument given as the string "function".

Did you perhaps mean

lua_getglobal(L,"function");
if(!lua_pcall(L,0,0,0)) 
{
 ... // succcess
} else {
    // examine the error from the call for useful information
    fprintf(stderr, "lua_pcall: %s\n", lua_tostring(L,1));
}

Edit: The error string returned from lua_pcall() is likely to be informative. For even more information, put a suitable error function on the stack as well, and pass its index as the 4th argument to lua_pcall. A good choice is debug.traceback.

void callback(lua_State *L, const char *fname) 
{
    int status
    lua_getglobal(L,"debug");       // put debug.traceback on the stack
    lua_getfield(L,-1,"traceback");
    lua_remove(L,-2);       
    lua_getglobal(L,fname);    // put function on the stack
    status = lua_pcall(L,0,0,-2)
    if (!status)        // call it with no parameters and no return values
    {
        // succcess
    } else {
        // examine the error from the call for useful information
        fprintf(stderr, "lua_pcall returned %d: %s\n", status, lua_tostring(L,1));
        lua_pop(L,1);               // remove error message from the stack
    }
    lua_pop(L,1);                   // remove debug.traceback from the stack
}

Edit2: After your clarification, it still doesn't make sense.

Your code has the following fragments:

lua_register(state,"function",function); //dozens of them
...

and later

lua_getglobal(L,"require");
lua_pushstring(L,"function");
if(!lua_pcall(L,1,0,0))
{
 ...

The first fragment creates a globals whose values are each C function. You would call those functions with get_global() and lua_pcall() as described in the first part of my answer.

The second fragment is retrieving the global named require and calling it with the string "function" as its only argument. The equivalent expressed in Lua is require"function", and it would be looking for a module named "function" in the usual way. Even when calling require(), it is a good idea to catch and report the error message. In this case, it is likely to tell you that there is no module named "function" in any of a long list of itemized places that require looked.

But nothing you've written actually invokes the function itself.

But there is a larger concern here. It isn't entirely clear why you need more than one Lua state in the first place, especially in a single-threaded program. Is it possible that [coroutines][2] are a better fit?

With multiple states, you must remember that each state is extremely isolated from all the others. The only way to move values from one state to another is through using the C API to retrieve values from one state and push them to the other. Coroutines give some of the advantages of separate states, while sharing a common set of globals.

RBerteig
Forgot writing the "require" statement pushed before it as the code was on a different computer, sorry for not being clear.
felace