Skip to content

Commit

Permalink
✨ 3.5.0 Release -- Fix a bunch of exception work and error reporting
Browse files Browse the repository at this point in the history
- 🛠️ Supports lua/* prefix for header inclusion of the lua library
- 🛠️ Use luaL_error to try and retain traceback information, even when compiled as C++ (don't catchall)
- 🛠️ Revise trampoline usage by changing automatic macro detection to be more precise (e.g. Building as C++ doesn't automatically enable catchalls
- 🛠️ Use safety argument checking for the object argument, to get better error messages in certain places
- 🛠️ Pull errors more appropriately (e.g. check directly for the sol::error / sol::detail::error_exception type to make sure it gets propagated properly
  • Loading branch information
ThePhD committed Feb 25, 2025
1 parent 336f76c commit 9190880
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 56 deletions.
12 changes: 8 additions & 4 deletions include/sol/call.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,8 @@ namespace sol {
"class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one class \"T\" "
"but then bind member methods from a complete unrelated class. Check things over!");
#if SOL_IS_ON(SOL_SAFE_USERTYPE)
auto maybeo = stack::check_get<Ta*>(L, 1);
stack::record tracking {};
auto maybeo = stack::stack_detail::check_get_arg<Ta*>(L, 1, &no_panic, tracking);
if (!maybeo || maybeo.value() == nullptr) {
return luaL_error(L,
"sol: received nil for 'self' argument (use ':' for accessing member functions, make sure member variables are "
Expand Down Expand Up @@ -516,7 +517,8 @@ namespace sol {
"to the class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one "
"class \"T\" but then bind member methods from a complete unrelated class. Check things over!");
#if SOL_IS_ON(SOL_SAFE_USERTYPE)
auto maybeo = stack::check_get<Ta*>(L, 1);
stack::record tracking {};
auto maybeo = stack::stack_detail::check_get_arg<Ta*>(L, 1, &no_panic, tracking);
if (!maybeo || maybeo.value() == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)");
Expand Down Expand Up @@ -574,7 +576,8 @@ namespace sol {
else {
using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>;
#if SOL_IS_ON(SOL_SAFE_USERTYPE)
auto maybeo = stack::check_get<Ta*>(L, 1);
stack::record tracking {};
auto maybeo = stack::stack_detail::check_get_arg<Ta*>(L, 1, &no_panic, tracking);
if (!maybeo || maybeo.value() == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)");
Expand Down Expand Up @@ -812,7 +815,8 @@ namespace sol {
using Ta = T;
using Oa = std::remove_pointer_t<object_type>;
#if SOL_IS_ON(SOL_SAFE_USERTYPE)
auto maybeo = stack::check_get<Ta*>(L, 1);
stack::record tracking {};
auto maybeo = stack::stack_detail::check_get_arg<Ta*>(L, 1, &no_panic, tracking);
if (!maybeo || maybeo.value() == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)");
Expand Down
12 changes: 9 additions & 3 deletions include/sol/compatibility/compat-5.3.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@
#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)
extern "C" {
#endif
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#if __has_include(<lua/lua.h>)
#include <lua/lua.h>
#include <lua/lauxlib.h>
#include <lua/lualib.h>
#else
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#endif
#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)
}
#endif
Expand Down
12 changes: 9 additions & 3 deletions include/sol/compatibility/compat-5.4.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@
#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)
extern "C" {
#endif
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#if __has_include(<lua/lua.h>)
#include <lua/lua.h>
#include <lua/lauxlib.h>
#include <lua/lualib.h>
#else
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#endif
#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)
}
#endif
Expand Down
69 changes: 46 additions & 23 deletions include/sol/compatibility/lua_version.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,32 @@
// clang-format off

#if SOL_IS_ON(SOL_USING_CXX_LUA)
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#elif SOL_IS_ON(SOL_USE_LUA_HPP)
#include <lua.hpp>
#else
extern "C" {
#if __has_include(<lua/lua.h>)
#include <lua/lua.h>
#include <lua/lauxlib.h>
#include <lua/lualib.h>
#else
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#endif
#elif SOL_IS_ON(SOL_USE_LUA_HPP)
#if __has_include(<lua/lua.hpp>)
#include <lua/lua.hpp>
#else
#include <lua.hpp>
#endif
#else
extern "C" {
#if __has_include(<lua/lua.h>)
#include <lua/lua.h>
#include <lua/lauxlib.h>
#include <lua/lualib.h>
#else
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#endif
}
#endif // C++ Mangling for Lua vs. Not

Expand All @@ -50,6 +66,8 @@
#endif
#elif defined(LUAJIT_VERSION)
#define SOL_USE_LUAJIT_I_ SOL_ON
#elif SOL_IS_ON(SOL_USING_CXX_LUAJIT)
#define SOL_USE_LUAJIT_I_ SOL_ON
#else
#define SOL_USE_LUAJIT_I_ SOL_DEFAULT_OFF
#endif // luajit
Expand Down Expand Up @@ -118,21 +136,25 @@
#else
#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_OFF
#endif
#elif SOL_LUAJIT_VERSION_I_ >= 20100
// LuaJIT 2.1.0-beta3 and better have exception support locked in for all platforms (mostly)
#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON
#elif SOL_LUAJIT_VERSION_I_ >= 20000
// LuaJIT 2.0.x have exception support only on x64 builds
#if SOL_IS_ON(SOL_PLATFORM_X64)
#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON
#else
#if SOL_IS_ON(SOL_USE_LUAJIT)
#if SOL_USE(SOL_LUAJIT_VERSION) >= 20100
// LuaJIT 2.1.0-beta3 and better have exception support locked in for all platforms (mostly)
#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON
#elif SOL_USE(SOL_LUAJIT_VERSION) >= 20000
// LuaJIT 2.0.x have exception support only on x64 builds
#if SOL_IS_ON(SOL_PLATFORM_X64)
#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON
#else
#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_OFF
#endif
#endif
#else
#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_OFF
// otherwise, there is no exception safety for
// shoving exceptions through Lua and errors should
// always be serialized
#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_OFF
#endif
#else
// otherwise, there is no exception safety for
// shoving exceptions through Lua and errors should
// always be serialized
#define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_OFF
#endif

// Some configurations work with exceptions,
Expand All @@ -144,13 +166,14 @@
#define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_USE_LUAJIT)
#define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_OFF
#elif SOL_IS_ON(SOL_USING_CXX_LUAJIT)
#if SOL_IS_ON(SOL_USE_LUAJIT) || SOL_IS_ON(SOL_USING_CXX_LUAJIT)
#define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_OFF
#elif SOL_IS_ON(SOL_USING_CXX_LUA)
// C++ builds of Lua will throw an exception to implement its `yield` behavior;
// it is irresponsible to "catch all" on this setting.
#define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_OFF
#else
// Otherwise, by default, everyhting should be caught.
#define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_ON
#endif
#endif
Expand Down
11 changes: 11 additions & 0 deletions include/sol/debug.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ namespace sol { namespace detail { namespace debug {
inline void print_section(const std::string& message, lua_State* L) {
std::cout << "-- " << message << " -- [ " << dump_types(L) << " ]" << std::endl;
}

inline void print_lua_information(lua_State* L) {
std::cout << "Lua Version: " << SOL_USE(SOL_LUA_VERSION) << std::endl;
std::cout << "Lua (C++): " << SOL_IS_ON(SOL_USING_CXX_LUA) << std::endl;
std::cout << "Trampoline Propagate Exceptions?: " << SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS) << std::endl;
std::cout << "Catch-all Exceptions?: " << SOL_IS_ON(SOL_EXCEPTIONS_CATCH_ALL) << std::endl;
std::cout << "LuaJIT: " << SOL_IS_ON(SOL_USE_LUAJIT) << std::endl;
std::cout << "LuaJIT Version: " << SOL_USE(SOL_LUAJIT_VERSION) << std::endl;
std::cout << "LuaJIT (C++): " << SOL_IS_ON(SOL_USING_CXX_LUAJIT) << std::endl;
std::cout << "LuaJIT Exception Trampoline: " << SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE) << std::endl;
}
}}} // namespace sol::detail::debug

#endif // SOL_DEBUG_HPP
25 changes: 19 additions & 6 deletions include/sol/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,23 @@ namespace sol {
}
return luaL_error(L, er.format_string, er.argument_strings[0], er.argument_strings[1], er.argument_strings[2], er.argument_strings[3]);
}

class error_exception : public std::runtime_error {
public:
error_exception(const std::string& str) : error_exception(detail::direct_error, "lua: error: " + str) {
}
error_exception(std::string&& str) : error_exception(detail::direct_error, "lua: error: " + std::move(str)) {
}
error_exception(detail::direct_error_tag, const std::string& str) : std::runtime_error(str) {
}
error_exception(detail::direct_error_tag, std::string&& str) : std::runtime_error(str) {
}

error_exception(const error_exception& e) = default;
error_exception(error_exception&& e) = default;
error_exception& operator=(const error_exception& e) = default;
error_exception& operator=(error_exception&& e) = default;
};
} // namespace detail

class error : public std::runtime_error {
Expand All @@ -69,19 +86,15 @@ namespace sol {
}
error(std::string&& str) : error(detail::direct_error, "lua: error: " + std::move(str)) {
}
error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), what_reason(str) {
error(detail::direct_error_tag, const std::string& str) : std::runtime_error(str) {
}
error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), what_reason(std::move(str)) {
error(detail::direct_error_tag, std::string&& str) : std::runtime_error(str) {
}

error(const error& e) = default;
error(error&& e) = default;
error& operator=(const error& e) = default;
error& operator=(error&& e) = default;

virtual const char* what() const noexcept override {
return what_reason.c_str();
}
};

} // namespace sol
Expand Down
21 changes: 16 additions & 5 deletions include/sol/error_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#ifndef SOL_ERROR_HANDLER_HPP
#define SOL_ERROR_HANDLER_HPP

#include <sol/config.hpp>
#include <sol/types.hpp>
#include <sol/demangle.hpp>

Expand Down Expand Up @@ -96,12 +97,16 @@ namespace sol {

inline int type_panic_string(lua_State* L, int index, type expected, type actual, string_view message = "") noexcept(false) {
push_type_panic_string(L, index, expected, actual, message, "");
return lua_error(L);
size_t str_size = 0;
const char* str = lua_tolstring(L, -1, &str_size);
return luaL_error(L, str);
}

inline int type_panic_c_str(lua_State* L, int index, type expected, type actual, const char* message = nullptr) noexcept(false) {
push_type_panic_string(L, index, expected, actual, message == nullptr ? "" : message, "");
return lua_error(L);
size_t str_size = 0;
const char* str = lua_tolstring(L, -1, &str_size);
return luaL_error(L, str);
}

struct type_panic_t {
Expand All @@ -118,15 +123,19 @@ namespace sol {
struct constructor_handler {
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
push_type_panic_string(L, index, expected, actual, message, "(type check failed in constructor)");
return lua_error(L);
size_t str_size = 0;
const char* str = lua_tolstring(L, -1, &str_size);
return luaL_error(L, str);
}
};

template <typename F = void>
struct argument_handler {
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
push_type_panic_string(L, index, expected, actual, message, "(bad argument to variable or function call)");
return lua_error(L);
size_t str_size = 0;
const char* str = lua_tolstring(L, -1, &str_size);
return luaL_error(L, str);
}
};

Expand All @@ -142,7 +151,9 @@ namespace sol {
aux_message += ")')";
push_type_panic_string(L, index, expected, actual, message, aux_message);
}
return lua_error(L);
size_t str_size = 0;
const char* str = lua_tolstring(L, -1, &str_size);
return luaL_error(L, str);
}
};

Expand Down
4 changes: 2 additions & 2 deletions include/sol/load_result.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ namespace sol {
if (valid()) {
return UT(nullopt);
}
return error(detail::direct_error, stack::get<std::string>(L, index));
return stack::stack_detail::get_error(L, index);
}
else {
if (!valid()) {
Expand All @@ -111,7 +111,7 @@ namespace sol {
type_panic_c_str(L, index, type_of(L, index), type::none, "expecting an error type (a string, from Lua)");
}
#endif // Check proxy type's safety
return error(detail::direct_error, stack::get<std::string>(L, index));
return stack::stack_detail::get_error(L, index);
}
else {
#if SOL_IS_ON(SOL_SAFE_PROXIES)
Expand Down
4 changes: 2 additions & 2 deletions include/sol/protected_function_result.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ namespace sol {
if (valid()) {
return UT();
}
return UT(error(detail::direct_error, stack::get<std::string>(L, target)));
return UT(stack::stack_detail::get_error(L, target));
}
else {
if (!valid()) {
Expand All @@ -133,7 +133,7 @@ namespace sol {
type_panic_c_str(L, target, t, type::none, "bad get from protected_function_result (is an error)");
}
#endif // Check Argument Safety
return error(detail::direct_error, stack::get<std::string>(L, target));
return stack::stack_detail::get_error(L, target);
}
else {
#if SOL_IS_ON(SOL_SAFE_PROXIES)
Expand Down
19 changes: 19 additions & 0 deletions include/sol/stack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <sol/stack_pop.hpp>
#include <sol/stack_field.hpp>
#include <sol/stack_probe.hpp>
#include <sol/error.hpp>
#include <sol/assert.hpp>

#include <cstring>
Expand Down Expand Up @@ -359,6 +360,24 @@ namespace sol {
(void)L;
#endif
}

namespace stack_detail {
inline error get_error(lua_State* L, int target) {
auto maybe_exc = stack::check_get<error&>(L, target);
if (maybe_exc.has_value()) {
return maybe_exc.value();
}
return error(detail::direct_error, stack::get<std::string>(L, target));
}

inline detail::error_exception get_error_exception(lua_State* L, int target) {
auto maybe_exc = stack::check_get<detail::error_exception&>(L, target);
if (maybe_exc.has_value()) {
return maybe_exc.value();
}
return detail::error_exception(detail::direct_error, stack::get<std::string>(L, target));
}
}
} // namespace stack
} // namespace sol

Expand Down
3 changes: 2 additions & 1 deletion include/sol/stack_check_unqualified.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ namespace sol { namespace stack {
}
else if constexpr (is_unique_usertype_v<T>) {
using element = unique_usertype_element_t<T>;
using element_no_cv = meta::unqualified_t<element>;
using actual = unique_usertype_actual_t<T>;
const type indextype = type_of(L_, index);
tracking.use(1);
Expand All @@ -229,7 +230,7 @@ namespace sol { namespace stack {
return true;
}
int metatableindex = lua_gettop(L_);
if (stack_detail::check_metatable<d::u<element>>(L_, metatableindex)) {
if (stack_detail::check_metatable<d::u<element_no_cv>>(L_, metatableindex)) {
void* memory = lua_touserdata(L_, index);
memory = detail::align_usertype_unique_destructor(memory);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
Expand Down
Loading

0 comments on commit 9190880

Please sign in to comment.