aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Labath <pavelo@centrum.sk>2011-05-19 12:58:31 (GMT)
committerPavel Labath <pavelo@centrum.sk>2013-02-16 23:19:15 (GMT)
commitd2c2c4f33a59b419145c33536fb7ea7acb36faf1 (patch)
treed4155e4fe5b22c3e10bff3f4f234d091f20f07b6
parent08e6c68912fdbf7c7f2011a3a754bbc8731fd231 (diff)
downloadfluxbox_pavel-d2c2c4f33a59b419145c33536fb7ea7acb36faf1.zip
fluxbox_pavel-d2c2c4f33a59b419145c33536fb7ea7acb36faf1.tar.bz2
Remove the possibility to transport exceptions through lua code
It's impossible to do this without C++0x features (we need std::exception_ptr).
-rw-r--r--src/FbTk/Luamm.cc61
-rw-r--r--src/FbTk/Luamm.hh2
2 files changed, 9 insertions, 54 deletions
diff --git a/src/FbTk/Luamm.cc b/src/FbTk/Luamm.cc
index ff3669f..3de86db 100644
--- a/src/FbTk/Luamm.cc
+++ b/src/FbTk/Luamm.cc
@@ -27,27 +27,11 @@
27namespace lua { 27namespace lua {
28 namespace { 28 namespace {
29 // keys for storing values in lua registry 29 // keys for storing values in lua registry
30 const char cpp_exception_metatable[] = "lua::cpp_exception_metatable";
31 const char cpp_function_metatable [] = "lua::cpp_function_metatable"; 30 const char cpp_function_metatable [] = "lua::cpp_function_metatable";
32 const char lua_exception_namespace[] = "lua::lua_exception_namespace"; 31 const char lua_exception_namespace[] = "lua::lua_exception_namespace";
33 const char this_cpp_object [] = "lua::this_cpp_object"; 32 const char this_cpp_object [] = "lua::this_cpp_object";
34 33
35 // converts C++ exceptions to strings, so lua can do something with them 34 typedef FbTk::Slot<int, state *> Slot;
36 int exception_to_string(lua_State *l)
37 {
38 std::exception_ptr *ptr = static_cast<std::exception_ptr *>(lua_touserdata(l, -1));
39 assert(ptr);
40 try {
41 std::rethrow_exception(*ptr);
42 }
43 catch(std::exception &e) {
44 lua_pushstring(l, e.what());
45 }
46 catch(...) {
47 lua_pushstring(l, ptr->__cxa_exception_type()->name());
48 }
49 return 1;
50 }
51 35
52 int absindex(lua_State *l, int index) throw() 36 int absindex(lua_State *l, int index) throw()
53 { return index<0 && -index<=lua_gettop(l) ? lua_gettop(l)+1+index : index; } 37 { return index<0 && -index<=lua_gettop(l) ? lua_gettop(l)+1+index : index; }
@@ -84,7 +68,7 @@ namespace lua {
84 lua_pop(l, 1); 68 lua_pop(l, 1);
85 69
86 try { 70 try {
87 cpp_function *fn = static_cast<cpp_function *>( L->touserdata(lua_upvalueindex(1)) ); 71 Slot *fn = static_cast<Slot *>( L->touserdata(lua_upvalueindex(1)) );
88 assert(fn); 72 assert(fn);
89 return (*fn)(L); 73 return (*fn)(L);
90 } 74 }
@@ -92,12 +76,11 @@ namespace lua {
92 // rethrow lua errors as such 76 // rethrow lua errors as such
93 e.push_lua_error(L); 77 e.push_lua_error(L);
94 } 78 }
79 catch(std::exception &e) {
80 L->pushstring(e.what());
81 }
95 catch(...) { 82 catch(...) {
96 // C++ exceptions (pointers to them, actually) are stored as lua userdata and 83 L->pushstring("Unknown exception");
97 // then thrown
98 L->createuserdata<std::exception_ptr>(std::current_exception());
99 L->rawgetfield(REGISTRYINDEX, cpp_exception_metatable);
100 L->setmetatable(-2);
101 } 84 }
102 85
103 // lua_error does longjmp(), so destructors for objects in this function will not be 86 // lua_error does longjmp(), so destructors for objects in this function will not be
@@ -238,21 +221,11 @@ namespace lua {
238 pushlightuserdata(this); 221 pushlightuserdata(this);
239 rawsetfield(REGISTRYINDEX, this_cpp_object); 222 rawsetfield(REGISTRYINDEX, this_cpp_object);
240 223
241 // a metatable for C++ exceptions travelling through lua code
242 newmetatable(cpp_exception_metatable);
243 lua_pushcfunction(cobj, &exception_to_string);
244 rawsetfield(-2, "__tostring");
245 pushboolean(false);
246 rawsetfield(-2, "__metatable");
247 pushdestructor<std::exception_ptr>();
248 rawsetfield(-2, "__gc");
249 pop();
250
251 // a metatable for C++ functions callable from lua code 224 // a metatable for C++ functions callable from lua code
252 newmetatable(cpp_function_metatable); 225 newmetatable(cpp_function_metatable);
253 pushboolean(false); 226 pushboolean(false);
254 rawsetfield(-2, "__metatable"); 227 rawsetfield(-2, "__metatable");
255 pushdestructor<FbTk::Slot<int, state *> >(); 228 pushdestructor<Slot>();
256 rawsetfield(-2, "__gc"); 229 rawsetfield(-2, "__gc");
257 pop(); 230 pop();
258 231
@@ -279,25 +252,7 @@ namespace lua {
279 throw std::bad_alloc(); 252 throw std::bad_alloc();
280 } 253 }
281 254
282 checkstack(3); 255 // wrap the lua exception and throw it
283 rawgetfield(REGISTRYINDEX, cpp_exception_metatable);
284 if(getmetatable(-2)) {
285 if(rawequal(-1, -2)) {
286 // it's a C++ exception, rethrow it
287 std::exception_ptr *ptr = static_cast<std::exception_ptr *>(touserdata(-3));
288 assert(ptr);
289
290 /*
291 * we create a copy, so we can pop the object without fearing the exception will
292 * be collected by lua's GC
293 */
294 std::exception_ptr t(*ptr); ptr = NULL;
295 pop(3);
296 std::rethrow_exception(t);
297 }
298 pop(2);
299 }
300 // it's a lua exception, wrap it
301 if(r == LUA_ERRERR) 256 if(r == LUA_ERRERR)
302 throw lua::errfunc_error(this); 257 throw lua::errfunc_error(this);
303 else 258 else
diff --git a/src/FbTk/Luamm.hh b/src/FbTk/Luamm.hh
index f39f3de..ca012c3 100644
--- a/src/FbTk/Luamm.hh
+++ b/src/FbTk/Luamm.hh
@@ -238,7 +238,7 @@ namespace lua {
238 const char* tocstring(int index, size_t *len = NULL) { return lua_tolstring(cobj, index, len); } 238 const char* tocstring(int index, size_t *len = NULL) { return lua_tolstring(cobj, index, len); }
239 // Don't use pushclosure() to create a __gc function. The problem is that lua calls them 239 // Don't use pushclosure() to create a __gc function. The problem is that lua calls them
240 // in an unspecified order, and we may end up destroying the object holding the 240 // in an unspecified order, and we may end up destroying the object holding the
241 // std::function before we get a chance to call it. This pushes a function that simply 241 // FbTk::Slot before we get a chance to call it. This pushes a function that simply
242 // calls ~T when the time comes. Only set it as __gc on userdata of type T. 242 // calls ~T when the time comes. Only set it as __gc on userdata of type T.
243 template<typename T> 243 template<typename T>
244 void pushdestructor() { lua_pushcfunction(cobj, &destroy_cpp_object<T>); } 244 void pushdestructor() { lua_pushcfunction(cobj, &destroy_cpp_object<T>); }