#define SOL_ALL_SAFETIES_ON 1 #include #include int main(int, char**) { std::cout << "=== script error handling ===" << std::endl; sol::state lua; std::string code = R"( bad&$#*$syntax bad.code = 2 return 24 )"; /* OPTION 1 */ // Handling code like this can be robust // If you disable exceptions, then obviously you would // remove the try-catch branches, and then rely on the // `lua_atpanic` function being called and trapping errors // there before exiting the application { // script_default_on_error throws / panics when the // code is bad: trap the error try { int value = lua.script( code, sol::script_default_on_error); // This will never be reached std::cout << value << std::endl; SOL_ASSERT(value == 24); } catch (const sol::error& err) { std::cout << "Something went horribly wrong: " "thrown error" << "\n\t" << err.what() << std::endl; } } /* OPTION 2 */ // Use the script_pass_on_error handler // this simply passes through the protected_function_result, // rather than throwing it or calling panic // This will check code validity and also whether or not it // runs well { sol::protected_function_result result = lua.script(code, sol::script_pass_on_error); SOL_ASSERT(!result.valid()); if (!result.valid()) { sol::error err = result; sol::call_status status = result.status(); std::cout << "Something went horribly wrong: " << sol::to_string(status) << " error" << "\n\t" << err.what() << std::endl; } } /* OPTION 3 */ // This is a lower-level, more explicit way to load code // This explicitly loads the code, giving you access to any // errors plus the load status then, it turns the loaded // code into a sol::protected_function which is then called // so that the code can run you can then check that too, for // any errors The two previous approaches are recommended { sol::load_result loaded_chunk = lua.load(code); SOL_ASSERT(!loaded_chunk.valid()); if (!loaded_chunk.valid()) { sol::error err = loaded_chunk; sol::load_status status = loaded_chunk.status(); std::cout << "Something went horribly wrong " "loading the code: " << sol::to_string(status) << " error" << "\n\t" << err.what() << std::endl; } else { // Because the syntax is bad, this will never be // reached SOL_ASSERT(false); // If there is a runtime error (lua GC memory // error, nil access, etc.) it will be caught here sol::protected_function script_func = loaded_chunk .get(); sol::protected_function_result result = script_func(); if (!result.valid()) { sol::error err = result; sol::call_status status = result.status(); std::cout << "Something went horribly wrong " "running the code: " << sol::to_string(status) << " error" << "\n\t" << err.what() << std::endl; } } } std::cout << std::endl; return 0; }