Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe Lua invoke C++ registered function

Tags:

c++

lua

Hey,everyone! I've a C++ app embedded Lua as script. A non-programmer edits the Lua script, then the C++ app invoke the Lua script and the Lua script also invokes C++ registered function.

I use Luaplus to do the above job. My question is: when the script-editor makes mistakes such as misspelling the the parameter, the C++ app crashes! What can I do to prevent this happening? thanks

like image 447
emliy Avatar asked Jan 26 '11 06:01

emliy


People also ask

How to call C function in Lua?

Moreover, for a C function to be called from Lua, we must register it, that is, we must give its address to Lua in an appropriate way. When Lua calls a C function, it uses the same kind of stack that C uses to call Lua. The C function gets its arguments from the stack and pushes the results on the stack.

What is a stack in Lua?

The Stack. Lua uses a virtual stack to pass values to and from C. Each element in this stack represents a Lua value ( nil , number, string, etc.). Whenever Lua calls C, the called function gets a new stack, which is independent of previous stacks and of stacks of C functions that are still active.

What is a Lua state?

The lua_State is basically a way to access what's going on in the Lua "box" during execution of your program and allows you to glue the two languages together.


1 Answers

Look at lua_cpcall and lua_pcall. They both allow protected function calls of lua in c. If they return a non-negative number then the call failed and the lua stack contains only the error string. In cpcalls case the stack is otherwise unmodified. For pcall you'll need to look at lua_pushcclosure to invoke a cfunction safely.

What you do is this: you create a c function with all of the lua_* calls you want, such as loadfile and dofile. You call this function using lua_cpcall or lua_pushcclosure amd lua_pcall. This allows you to detect if an error occured in t he function you passed to cpcall.

Examples:

function hello() {
  string hello_ = "Hello Lua!";
  struct C {
    static int call(lua_State* L) {
      C *p = static_cast<C*>(lua_touserdata(L,-1));
      lua_pushstring(L, p->str.c_str() );
      lua_getglobal(L, "print"); 
      lua_call(L, 1, 0); //ok
      lua_pushstring(L, p->str.c_str() );
      lua_getglobal(L, "notprint"); 
      lua_call(L, 1, 0); //error -> longjmps
      return 0; //Number of values on stack to 'return' to lua
    }
    const string& str;
  } p = { hello_ };
  //protected call of C::call() above
  //with &p as 1st/only element on Lua stack
  //any errors encountered will trigger a longjmp out of lua and
  //return a non-0 error code and a string on the stack
  //A return of 0 indicates success and the stack is unmodified
  //to invoke LUA functions safely use the lua_pcall function
  int res = lua_cpcall(L, &C::call, &p);
  if( res ) {
    string err = lua_tostring(L, -1);
    lua_pop(L, 1);
    //Error hanlder here
  }
  //load a .lua file
  if( (res=luaL_loadfile(L, "myLuaFile.lua")) ) {
    string err = lua_tostring(L, -1);
    lua_pop(L, 1);
    //res is one of
    //LUA_ERRSYNTAX - Lua syntax error
    //LUA_ERRMEM    - Out of memory error
    //LUE_ERRFILE   - File not found/accessible error
  }
  //execute it
  if( (res=lua_pcall(L,0,0,0)) ) {
    string err = lua_tostring(L, -1);
    lua_pop(L, 1);
    // res is one of
    // LUA_ERRRUN: a runtime error.
    // LUA_ERRMEM: memory allocation error.
    // LUA_ERRERR: error while running the error handler function (NULL in this case).
  }
  // try to call [a_int,b_str] = Foo(1,2,"3")
  lua_getglobal(L,"Foo");
  if( lua_isfunction(L,lua_gettop(L)) ) { //Foo exists
    lua_pushnumber(L,1);
    lua_pushnumber(L,2);
    lua_pushstring(L,"3");
    lua_pushvalue(L, -4); //copy of foo()

    if( (res = lua_pcall(L, 3, 2, 0/*default error func*/)) ) {
      string err = lua_tostring(L, -1);
      lua_pop(L, 1);
      //error: see above
    }
    int a_int = (int)lua_tointeger(L,-2);
    string b_str = lua_tostring(L,-1);
    lua_pop(L,2+1); //2 returns, + extra copy of Foo()
  }
}
like image 169
KitsuneYMG Avatar answered Sep 30 '22 12:09

KitsuneYMG