diff options
author | Pavel Labath <pavelo@centrum.sk> | 2011-05-19 12:58:31 (GMT) |
---|---|---|
committer | Pavel Labath <pavelo@centrum.sk> | 2013-02-16 23:19:15 (GMT) |
commit | d2c2c4f33a59b419145c33536fb7ea7acb36faf1 (patch) | |
tree | d4155e4fe5b22c3e10bff3f4f234d091f20f07b6 | |
parent | 08e6c68912fdbf7c7f2011a3a754bbc8731fd231 (diff) | |
download | fluxbox_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.cc | 61 | ||||
-rw-r--r-- | src/FbTk/Luamm.hh | 2 |
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 @@ | |||
27 | namespace lua { | 27 | namespace 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>); } |