1

Im working on a server in C that dynamically generating Lua commands on the fly and send them by socket to the clients. Right now the server is using plain text, but I would like the server to pre-compile the script before sending it to the clients.

I check luac.c but couldn't find how to be able to do something like this:

char lua_commands[ 1024 ] = { "a = 123; b = 456; c = a + b;" };

int socket 
unsigned int send_buffer_size
unsigned char *send_buffer

/* Compile lua_commands and store the binary script into send_buffer without
having to write first the .out on disk then read it again in order store the content
into send_buffer */

send( socket, send_buffer, send_buffer_size, 0 );

Anybody can help me to achieve this?

[ Update ]

Ok, I think I figure it out:

#include "lua.h"
#include "lauxlib.h"
#include "ldo.h"
#include "lfunc.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstring.h"
#include "lundump.h"


#define toproto(L,i) (clvalue(L->top+(i))->l.p)

static int writer( lua_State *L, const void *p, size_t size, void *u ){

    unsigned int i = 0;

    unsigned char *d = ( unsigned char * )p;

    // Print all the bytes on the console.
    while( i != size ) {
        printf("%d ", d[ i ] );
        ++i;
    }
    return 0;
}


void compile( lua_State *L, char *command ){

    const Proto* f;

    if (luaL_loadstring( L, command ) !=0 ) {
        printf( "%s\n", lua_tostring( L, -1 ) );
    }

    f = toproto( L,-1 );

    lua_lock( L );

    luaU_dump( L, f, writer, NULL, 1 );

    lua_unlock( L );    
}


int main (int argc, const char * argv[]) {

    lua_State *L = lua_open(); 

    compile( L, "a = 123; b = 456; c = a + b; print( c );" );

    lua_close( L );

    return 0;
}

However that leads me to another question, do I have to close and reopen (lua_open, lua_close) the Lua state every time I'm calling my compile() function with other Lua commands or the output will only be the result of the latest luaL_loadstring?

Im not sure but look to me from the toproto macro definition that the top most stack will be returned am I correct?

2
  • 4
    possible duplicate of Compile lua code, store bytecode then load and execute it Commented Mar 5, 2012 at 5:55
  • 2
    Note that leaving the message in Lua source text rather than bytecode may have several benefits. Off the top of my head... first, bytecode is often not smaller. Second, bytecode is very platform dependent. Third, bytecode is very difficult to verify as safe. If size is a concern, you can always generate messages using short identifiers, minimal whitespace, and without comments. You can also use compression on the wire which will help for larger messages. Commented Mar 5, 2012 at 22:27

1 Answer 1

0

You should use lua_dump() instead of internal toproto() + luaU_dump() functions. As an added bonus, this way your code will support LuaJIT 2.

It is not necessary to recreate the state each time you get the dump.

BUT. I would avoid executing Lua bytecode that came from the untrusted source (and server often is untrusted to the client). It is not safe, and may lead to severe security issues. (No such problems with source code — but you still have to sandbox it, of course.)

In general, always make sure that you check that the code you load from untrusted source is not bytecode (it is, if first byte is 27 decimal). Always execute such code in a sandbox.


If all that you need is to pass data in Lua-friendly way, pick some proper data serialization library instead. Aside of sandboxing and portability problems, loadstring() is rather slow.

For example, we're using using my luatexts library for similar purposes (make sure to pore through this list for alternatives). Luatexts supports tuples, which plays nicely with function calls. For example (in pseudocode):

Server:

my_send(luatexts.lua.save("myMethod", { param = true }, 42))

Client:

local actions = { }

function actions.myMethod(params, number)
  print(params.param, number) --> true, 42
end

local function handle_action(ok, name, ...)
  assert(ok, name) -- name would contain error message if not OK
  local handler = assert(actions[name], "unknown action")
  return handler(...)
end

local str = my_receive()

handle_action(luatexts.load(str))

Open a ticket if you want luatexts.save or streaming support implemented in C.

Sign up to request clarification or add additional context in comments.

3 Comments

Could You please add some arguments about using lua_dump() instead toproto() + luaU_dump()? By default it does not strip debug info.
In general you should not use private Lua internals directly — as well as private internals of any other library. If you want to hack away and use them — you're on your own.
i'd agree only if public interface fits an exact needs of the library. In my case it does not. Worst thing - in the near future it's going to fit even less. So, while the Lua library is OpenSource, i'd prefer hacking it all the way down to get the functionality exact project requires. Btw, LuaJIT argument is good. But small. I'd like to hear some more of those :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.