'Lua set default error handler

The default lua_pcall error handler (as of Lua 5.3) does nothing, letting the exception message remain on top of the stack. We would like to change this so we get a luaL_traceback traceback in addition to the exception message on top of the stack on lua_pcall failure.

Unfortunately I think that means we need to insert the error handler just below all of our pcalls. The most robust way of doing this seems to be like this:

/* push function and arguments */
lua_pushstuff...

/* push error handler */
lua_pushcfunction(L, my_error_handler);

/* move the error handler just below the function and arguments */
lua_insert(L, -(number of args + 1));

if (lua_pcall(L, nargs, nresults, -(number of args + 1))) {
    /* error here (my_error_handler was invoked) */
    /* do something with lua_tostring(L, -1) */
}

/* afterwards, pop the error handler (it may be below return values) */
lua_pop(L, 1);

But this introduces noise at each pcall (we have quite a few, since we have some Lua callbacks called asynchronously from C) and feels kind of repetitive. I thought this could be wrapped inside some lua_mypcall function that does this setup work automatically, but I have two questions:

  1. is this approach liable to break with more complex stack manipulation before (or inside) the pcall? (I'm not super well versed in the Lua stack yet)

  2. since we'd like the traceback on the majority of pcalls, it makes sense to make this error handler the default, and having the previous error handler (that does nothing) be specified manually, so is there a way to globally change the default error handler for the Lua state?

I saw that lua_pcallk has some code for errfunc == 0, but it doesn't seem configurable. We could hack the Lua implementation to change the default manually, but would like to avoid that.

We are using Lua 5.3. Thanks.



Solution 1:[1]

Your basic approach is sound, but you are missing a lua_remove (instead of lua_pop) and your stack indices are wrong. Try this:

int lua_mypcall( lua_State* L, int nargs, int nret ) {
  /* calculate stack position for message handler */
  int hpos = lua_gettop( L ) - nargs;
  int ret = 0;
  /* push custom error message handler */
  lua_pushcfunction( L, my_error_handler );
  /* move it before function and arguments */
  lua_insert( L, hpos );
  /* call lua_pcall function with custom handler */
  ret = lua_pcall( L, nargs, nret, hpos );
  /* remove custom error message handler from stack */
  lua_remove( L, hpos );
  /* pass return value of lua_pcall */
  return ret;
}

Solution 2:[2]

if (lua_pcall(L,0,0,0)!=LUA_OK) fprintf(stderr,"%s\n", lua_tostring(L,-1) );

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 siffiejoe
Solution 2 superbem