sol2: stack is not properly unwound on lua errors
Take this example code:
#include <sol.hpp>
#include <iostream>
struct Noisy
{
Noisy() { std::cerr << "ctor" << std::endl; }
~Noisy() { std::cerr << "dtor" << std::endl; }
};
int foo(sol::function fun)
{
Noisy n;
return fun();
}
int main(int argc, char** argv)
{
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::package);
lua.set_function("foo", &foo);
try { lua.script("foo()"); }
catch (const sol::error& e) { std::cerr << "Caught: " << e.what() << std::endl; }
lua.script("print(foo(function() return 3 end))");
return 0;
}
If I compile it with lua5.1 or 5.2, I get the following output:
ctor
Caught: lua: error: attempt to call a nil value
ctor
dtor
3
In the first case, it doesn’t run the destructor of the noisy class. Looks like lua longjmps out of the function, and only calls atpanic after this, thus throw won’t properly unwind the stack. Not sure if we can do anything about it, other than wrapping anything that can fail inside a ©pcall (but that would probably have disastrous consequences on performance…), or requiring a lua built with c++ and c++ exceptions instead of this setjmp/longjmp madness (but that would probably kill abi compatibility with existing lua libs).
By the way, this is what I get if I compile with luajit on x64 linux:
ctor
dtor
Caught: lua: error: caught (...) exception
ctor
dtor
3
Here at least the destructor runs correctly, but the error message disappears. (Calling fun will throw an exception that can be caught as (…) on the C++ side, if we run on a platform with full exception interoperability. On windows/x86, who knows what the hell will happen.)
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 15 (9 by maintainers)
Changing the
sol::functiontosol::protected_functionseems to fix the problem. I opened issue #65 yesterday having similar issues with sol::function.Part of ThePhD’s response:
Right now,
sol::functionis presented as THE way to handle Lua functions in C++, but it’s very dangerous to use. I think the difference betweensol::functionandsol::protected_functionisn’t immediately clear.Personally, I would prefer
sol::functionbeing namedsol::unprotected_functionandsol::protected_functionbeing namedsol::function. The usage seems more clear to me here.Of course, that isn’t necessarily the best route. Mentioning the difference between the function types in the tutorial might be just as good of a solution.