lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hello,

There was a similar discussion taking place in 2010,
http://lua-users.org/lists/lua-l/2010-04/msg00441.html, but it
doesn't seem to clarify our case.

We use LuaJIT Beta9 and experience intermittent trouble with
exceptions thrown from lua_atpanic handler. Beta10 demonstrates
the same behaviour.

The problem seems to depend on the compiler version (in case of
gcc), language flavour (C++ vs Objective C), platform (32-bit
Linux, 64-bit Linux, Darwin).

The common part is that the problem always manifests itself
in almost the same way: an exception, thrown from an at_panic handler,
instead of percolating up the stack ends up in the same stack
frame, and recursively executes the at_panic handler again.

I attach two test cases (in C++ and Objective C) which can
be used to demonstrate the issue.

I would appreciate any help, explanation of the cause, or
description of a workaround. 

Being able to propagate exceptions through LuaJIT stack is a nice
feature of LuaJIT and we use it quite extensively.

Thank you,

---------------------------------------------------------------
#include <objc/Object.h>
#include <objc/runtime.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"


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

@implementation Exception
+ (id) alloc
{
	static char buf[10000];
	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-beta9/src tarantool_lua.m -L
/home/kostja/LuaJIT-2.0.0-beta9/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-beta9/src tarantool_lua.m -L
/home/kostja/LuaJIT-2.0.0-beta9/src -lluajit -ldl -lobjc; ./a.out       
exception handled
kostja@atlas:~$ clang++ -fexceptions
-I/home/kostja/LuaJIT-2.0.0-beta9/src tarantool_lua.m -L
/home/kostja/LuaJIT-2.0.0-beta9/src -lluajit -ldl -lobjc; ./a.out
exception handled

--------------------------------------------------------------
#include <cstdlib>
#include <lua.hpp>

static int panic = 0;

static int lua_panic_cb(lua_State *L) {
	if (!panic++)
		throw 0;
	abort();
	return 0;
}

int
main(int argc, char * argv[])
{
	lua_State *L = luaL_newstate();
	if (L == NULL)
		return 1;
	lua_atpanic(L, lua_panic_cb);
	try {
		lua_pushstring(L, "uncallable");
		lua_call(L, 0, LUA_MULTRET);
	} catch (...) {
		/* If we're lucky, we should get here. */
	}
	lua_close(L);
	return 0;
}
--------------------------------------------------------------

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