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.

Attachment: pgpiQj3LdKdhc.pgp
Description: PGP signature

Reply via email to