Hello,

While porting tarantool to compile with CLang on Linux, an old bug
with infinite recursion in LuaJIT on exception reappeared.

The bug manifests itself in the same way as described in 
https://bugs.launchpad.net/tarantool/+bug/882000

Interestingly, our own test case which Dmitry put up a while
ago to detect this bug (luatest.cpp in cmake/) does not catch
it.

After some trail and error, I was able to come up with
a reduced test case, which, when compiled with gcc, works
well, and when compiled with clang, breaks with infinite
recursion.

Let me quote it here (the file is also attached):
---------------------------------------------------------------
#include <objc/Object.h>
#include <objc/runtime.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

#include "lj_obj.h"
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lj_cconv.h"
#include "lj_state.h"

@interface Exception: Object {
        char *errmsg;
}
+ (id) alloc;
- (id) init: (char*) msg;
@end

@implementation Exception
+ (id) alloc
{
        static char buf[sizeof(Exception)];
        Exception *new = (Exception *) buf;
        object_setClass(new, self);
        return new;
}

- (id) init: (char*) msg;
{
        self = [super init];
        errmsg = msg;
        return self;
}
@end

void test(struct lua_State *L)
{
        const char *format = luaL_checkstring(L, 1);
}

static int
box_lua_panic(struct lua_State *L)
{
        static int invocation_count = 0;
        if (invocation_count++ == 0)
                @throw [[Exception alloc] init: "message"];
        abort();
}

int main()
{
        lua_State *L = luaL_newstate();
        luaL_openlibs(L);
        lua_atpanic(L, box_lua_panic);
        @try {
                test(L);
        } @catch (Exception *e) {
                printf("exception handled\n");
        }
        lua_close(L);
}
----------------------------------------------------------------------

An example of how it works and breaks:

kostja@atlas:~$ clang++ -fobjc-exceptions
-I/home/kostja/LuaJIT-2.0.0-beta10/src tarantool_lua.m -L
/home/kostja/LuaJIT-2.0.0-beta10/src -lluajit -ldl -lobjc; ./a.out
[1]    20790 abort (core dumped)  ./a.out
kostja@atlas:~$ g++ -fobjc-exceptions
-I/home/kostja/LuaJIT-2.0.0-beta10/src tarantool_lua.m -L
/home/kostja/LuaJIT-2.0.0-beta10/src -lluajit -ldl -lobjc; ./a.out       
exception handled
kostja@atlas:~$ clang++ -fexceptions
-I/home/kostja/LuaJIT-2.0.0-beta10/src tarantool_lua.m -L
/home/kostja/LuaJIT-2.0.0-beta10/src -lluajit -ldl -lobjc; ./a.out
exception handled

Apparently, there are two exception information formats: "right",
i.e. the one with which LuaJIT works well, and "wrong", i.e. the
one with which LuaJIT breaks.

The "right" format happens to be used by default for C++, 
both by gcc and clang.
The "wrong" format is used for Objective C only ,and only for
clang: gcc apparently uses the same format both for C++ and gcc
exceptions. 

Another observation is that it doesn't matter how you compile
LuaJIT: what matters is how you compile the host program.

I'll keep digging why we have this, but this is what I think
needs to be done in the meanwhile:

- we need to add the above test case to cmake
- when building tarantool, even with bundled luajit, we need to be
running the test and aborting the build if options are not right.

-- 
http://tarantool.org - an efficient, extensible in-memory data store

_______________________________________________
Mailing list: https://launchpad.net/~tarantool-developers
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~tarantool-developers
More help   : https://help.launchpad.net/ListHelp

Reply via email to