Enrico Tassi <gareuselesi...@debian.org> writes: > On Wed, Dec 09, 2009 at 09:42:18AM +0100, Erich Schubert wrote: >> As far as I know (from discussion with upstream and on #debian-devel) it >> is currently impossible for me to re-use the Debian lua packages for building >> Enigma. The main reason is that C++ exceptions and lua compiled for C use >> will break badly. > > I would be happy to provide a C++ version of the runtime, and would be > easy. What refrains me is that from the C++ interpreter you will be > allowed to load C modules (shipped in liblua5.1-* packages) but there > you will face the same problem I believe.
I'm looking at this wishlist bug because of Bos Wars, which is written in C++ and uses Lua and tolua++ (but no Lua modules from separate packages). Currently, the exception handling in Bos Wars is a mess; C++ code very often calls Lua functions, and if they throw errors (e.g. type mismatch, out of memory), then Bos Wars typically leaks std::string and other objects. Although C++ permits that longjmp might call destructors, I have verified that it does not call them on Debian. Fixing the leaks with the current liblua5.1.so seems possible but very cumbersome and error-prone. Furthermore, tolua++ would also have to be changed, because it nowadays generates code that assumes strings will be destroyed on exceptions. I don't see why Lua modules compiled as C would have a problem with liblua5.1 using C++ exceptions. Although LUAI_THROW and LUAI_TRY are defined in luaconf.h, which is installed in liblua5.1-0-dev, modules and applications cannot use these macros. The macros require struct lua_jmpbuf and struct lua_State from lstate.h, which is not installed. Even in lua5.1 itself, only the luaD_throw function uses LUAI_THROW, and only the luaD_rawrunprotected function uses LUAI_TRY. Everything that needs to throw or handle errors then uses these functions. Throwing an exception from luaD_throw in liblua5.1.so, correctly propagating it through a module, and catching it in luaD_rawrunprotected in liblua5.1.so may require that the module has been compiled with some kind of exception handling data, so that the unwinder can find the calling function and check whether it wanted to catch the exception. However, it looks like GCC always generates .cfi_startproc and related pseudo-ops nowadays, and these then become an .eh_frame section in the binary. I got those even when compiling C for x86 with both -fno-exceptions and -fno-unwind-tables. Just setting CC=g++ in lua5.1-5.1.4/src/Makefile causes the function names in the shared library to become mangled, making the library binary-incompatible with current modules and applications. Because applications written in C will not be able to use the mangled names, the C and C++ variants of the library would have to be installed side by side, or some extern "C" would have to be added. If there are no other incompatibilities, then I think extern "C" would be best, because it does not require twice the disk space. When built as C++, LUAI_TRY catches all C++ exceptions, even ones like std::bad_alloc that were not thrown by LUAI_THROW. This makes sense because the Lua stack should be unwound even in that case. However, it looks like Lua will then not set an error message on the Lua stack and will leave some other object there instead. This situation is fortunately easy to avoid, by catching all C++ exceptions in C++ functions called from Lua, and translating them to lua_error calls. This requires only one try...catch per function, so it is much easier than catching all Lua errors in C++ code that calls Lua.
pgpiQj3LdKdhc.pgp
Description: PGP signature