Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle C++ exceptions when calling functions from Lua?

Tags:

I have a working C++ function that I am able to call from Lua. To demonstrate my problem here is an example:

int PushHello(lua_State *L){     string str("Hello");     lua_pushlstring(L, str.data(), str.length());     return 1; } 

Note: I know I don't have to use string variable there, but it is there to demonstrate the problem.

Here are my two problems:

  1. When I call this function from Lua string constructor may throw an exception. Is that a problem? Will Lua handle it and unwind the Lua stack properly? I don't think so. How can I solve that? Do I need to add try/catch around all such code and convert the exception to lua_error? Is not there a better solution?

  2. Another problem that I have probably solved by compiling Lua as C++ is when lua_pushlstring() calls lua_error() string destructor would not be called if longjmp was used. Is the problem solved by compiling as C++ and throwing exceptions instead of using longjmp?

To clarify, possible solution I can see to problem 1 would be this:

int PushHello(lua_State *L){     string str;     try{         str.assign("Hello");     catch(exception &e){         luaL_error(L, e.what());     }     lua_pushlstring(L, str.data(), str.length());     return 1; } 

But that is very ugly and error prone as try/catch would need to be added to many places. It could be done as a macro and put around every command that can throw, but that would not be much nicer.

like image 951
Juraj Blaho Avatar asked Jan 06 '11 14:01

Juraj Blaho


People also ask

How do I catch exceptions in Lua?

If you need to handle errors in Lua, you should use the pcall function (protected call) to encapsulate your code. Of course, you can call pcall with an anonymous function: if pcall(function () ...

What does pcall do in Lua?

Lua Error Handling Using pcall pcall stands for "protected call". It is used to add error handling to functions. pcall works similar as try-catch in other languages. The advantage of pcall is that the whole execution of the script is not being interrupted if errors occur in functions called with pcall .

Can C handle exceptions?

The C programming language does not support exception handling nor error handling. It is an additional feature offered by C. In spite of the absence of this feature, there are certain ways to implement error handling in C. Generally, in case of an error, most of the functions either return a null value or -1.

Can you throw exceptions in C?

C doesn't support exceptions. You can try compiling your C code as C++ with Visual Studio or G++ and see if it'll compile as-is. Most C applications will compile as C++ without major changes, and you can then use the try... catch syntax.


2 Answers

I have found a reasonable solution. The question is whether it is correct. Instead of exporting (or calling via lua_cpcall) the original function int PushHello(lua_State *L) a wrapper int SafeFunction<PushHello>(lua_State *L) is exported/called. The wrapper looks like:

template<lua_CFunction func> int SafeFunction(lua_State *L){     int result = 0;     try{         result = func(L);     }     // transform exception with description into lua_error     catch(exception &e){         luaL_error(L, e.what());     }     // rethrow lua error - C++ Lua throws lua_longjmp*     catch(lua_longjmp*){         throw;     }     // any other exception as lua_error with no description     catch(...){         luaL_error(L, "Unknown error");     }      return result; } 

What do you think about it? Do you see any problems?

like image 73
Juraj Blaho Avatar answered Nov 08 '22 16:11

Juraj Blaho


Juraj Blaho's answer is great. It has however a drawback: for each function you export with int SafeFunction<PushHello>(lua_State *L), the compiler will generate a copy of all code from the template, just as if it was a macro. When numerous small functions are exported, this will be a waste of footprint.

You can easily avoid the problem by defining a common static function performing all the job, and the template function just calls that common function:

static int SafeFunctionCommon(lua_State *L, lua_CFunction func){     int result = 0;     try{         result = func(L);     }     // transform exception with description into lua_error     catch(exception &e){         luaL_error(L, e.what());     }     // rethrow lua error - C++ Lua throws lua_longjmp*     catch(lua_longjmp*){         throw;     }     // any other exception as lua_error with no description     catch(...){         luaL_error(L, "Unknown error");     }      return result; }  template<lua_CFunction func> int SafeFunction(lua_State *L){     return SafeFunctionCommon(L, func); } 
like image 24
prapin Avatar answered Nov 08 '22 16:11

prapin