Skip to content

Commit ce32549

Browse files
committed
Remove as many of the std::string error handlers as possible to avoid memory leaks in C mode
Add some checks for container usertypes that masquerade as convertible from tables Make sure shared_ptr-like types that are copyable are returned directly (but do not do this for move-only types)
1 parent 88355fc commit ce32549

File tree

9 files changed

+328
-260
lines changed

9 files changed

+328
-260
lines changed

include/sol/call.hpp

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ namespace sol {
147147
typedef meta::tuple_types<typename traits::return_type> return_types;
148148
typedef typename traits::free_args_list args_list;
149149
// compile-time eliminate any functions that we know ahead of time are of improper arity
150-
if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
150+
if constexpr (!traits::runtime_variadics_t::value
151+
&& meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
151152
return overload_match_arity(types<Fxs...>(),
152153
std::index_sequence<In...>(),
153154
std::index_sequence<M...>(),
@@ -161,25 +162,25 @@ namespace sol {
161162
if constexpr (!traits::runtime_variadics_t::value) {
162163
if (traits::free_arity != fxarity) {
163164
return overload_match_arity(types<Fxs...>(),
164-
std::index_sequence<In...>(),
165-
std::index_sequence<traits::free_arity, M...>(),
166-
std::forward<Match>(matchfx),
167-
L,
168-
fxarity,
169-
start,
170-
std::forward<Args>(args)...);
165+
std::index_sequence<In...>(),
166+
std::index_sequence<traits::free_arity, M...>(),
167+
std::forward<Match>(matchfx),
168+
L,
169+
fxarity,
170+
start,
171+
std::forward<Args>(args)...);
171172
}
172173
}
173174
stack::record tracking{};
174175
if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) {
175176
return overload_match_arity(types<Fxs...>(),
176-
std::index_sequence<In...>(),
177-
std::index_sequence<M...>(),
178-
std::forward<Match>(matchfx),
179-
L,
180-
fxarity,
181-
start,
182-
std::forward<Args>(args)...);
177+
std::index_sequence<In...>(),
178+
std::index_sequence<M...>(),
179+
std::forward<Match>(matchfx),
180+
L,
181+
fxarity,
182+
start,
183+
std::forward<Args>(args)...);
183184
}
184185
return matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
185186
}
@@ -237,7 +238,8 @@ namespace sol {
237238
typedef meta::tuple_types<typename traits::return_type> return_types;
238239
typedef typename traits::free_args_list args_list;
239240
// compile-time eliminate any functions that we know ahead of time are of improper arity
240-
if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
241+
if constexpr (!traits::runtime_variadics_t::value
242+
&& meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
241243
return overload_match_arity(types<Fx1, Fxs...>(),
242244
std::index_sequence<I1, In...>(),
243245
std::index_sequence<M...>(),
@@ -251,25 +253,25 @@ namespace sol {
251253
if constexpr (!traits::runtime_variadics_t::value) {
252254
if (traits::free_arity != fxarity) {
253255
return overload_match_arity(types<Fx1, Fxs...>(),
254-
std::index_sequence<I1, In...>(),
255-
std::index_sequence<traits::free_arity, M...>(),
256-
std::forward<Match>(matchfx),
257-
L,
258-
fxarity,
259-
start,
260-
std::forward<Args>(args)...);
256+
std::index_sequence<I1, In...>(),
257+
std::index_sequence<traits::free_arity, M...>(),
258+
std::forward<Match>(matchfx),
259+
L,
260+
fxarity,
261+
start,
262+
std::forward<Args>(args)...);
261263
}
262264
}
263265
stack::record tracking{};
264266
if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) {
265-
return overload_match_arity(types<Fx1, Fxs...>(),
266-
std::index_sequence<I1, In...>(),
267-
std::index_sequence<M...>(),
268-
std::forward<Match>(matchfx),
269-
L,
270-
fxarity,
271-
start,
272-
std::forward<Args>(args)...);
267+
return overload_match_arity(types<Fx1, Fxs...>(),
268+
std::index_sequence<I1, In...>(),
269+
std::index_sequence<M...>(),
270+
std::forward<Match>(matchfx),
271+
L,
272+
fxarity,
273+
start,
274+
std::forward<Args>(args)...);
273275
}
274276
return matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
275277
}
@@ -330,7 +332,7 @@ namespace sol {
330332

331333
template <typename Fx, typename... Args>
332334
static int call(lua_State* L, Fx&& f, Args&&... args) {
333-
if constexpr(is_lua_reference_v<meta::unqualified_t<Fx>>) {
335+
if constexpr (is_lua_reference_v<meta::unqualified_t<Fx>>) {
334336
if constexpr (is_index) {
335337
return stack::push(L, std::forward<Fx>(f), std::forward<Args>(args)...);
336338
}
@@ -373,6 +375,7 @@ namespace sol {
373375
}
374376
else {
375377
if constexpr (std::is_const_v<meta::unwrapped_t<T>>) {
378+
(void)f;
376379
return luaL_error(L, "sol: cannot write to a readonly (const) variable");
377380
}
378381
else {
@@ -502,8 +505,13 @@ namespace sol {
502505
else {
503506
using returns_list = typename wrap::returns_list;
504507
using caller = typename wrap::caller;
505-
return stack::call_into_lua<checked, clean_stack>(
506-
returns_list(), types<>(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), std::forward<Args>(args)...);
508+
return stack::call_into_lua<checked, clean_stack>(returns_list(),
509+
types<>(),
510+
L,
511+
boost + (is_variable ? 3 : 2),
512+
caller(),
513+
std::forward<Fx>(fx),
514+
std::forward<Args>(args)...);
507515
}
508516
}
509517
else {
@@ -528,16 +536,16 @@ namespace sol {
528536
using caller = typename wrap::caller;
529537
if constexpr (sizeof...(Args) > 0) {
530538
return stack::call_into_lua<checked, clean_stack>(types<void>(),
531-
args_list(),
532-
L,
533-
boost + (is_variable ? 3 : 2),
534-
caller(),
535-
std::forward<Fx>(fx),
536-
std::forward<Args>(args)...);
539+
args_list(),
540+
L,
541+
boost + (is_variable ? 3 : 2),
542+
caller(),
543+
std::forward<Fx>(fx),
544+
std::forward<Args>(args)...);
537545
}
538546
else {
539547
using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>;
540-
#if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE
548+
#if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE
541549
auto maybeo = stack::check_get<Ta*>(L, 1);
542550
if (!maybeo || maybeo.value() == nullptr) {
543551
if (is_variable) {
@@ -547,12 +555,12 @@ namespace sol {
547555
}
548556
object_type* po = static_cast<object_type*>(maybeo.value());
549557
object_type& o = *po;
550-
#else
558+
#else
551559
object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1));
552-
#endif // Safety
560+
#endif // Safety
553561

554562
return stack::call_into_lua<checked, clean_stack>(
555-
types<void>(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), o);
563+
types<void>(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), o);
556564
}
557565
}
558566
}
@@ -727,8 +735,7 @@ namespace sol {
727735

728736
template <typename F, typename... Args>
729737
static int call(lua_State* L, F&& f, Args&&... args) {
730-
constexpr bool is_specialized = meta::any<
731-
std::is_same<U, detail::no_prop>,
738+
constexpr bool is_specialized = meta::any<std::is_same<U, detail::no_prop>,
732739
meta::is_specialization_of<U, var_wrapper>,
733740
meta::is_specialization_of<U, constructor_wrapper>,
734741
meta::is_specialization_of<U, constructor_list>,
@@ -747,7 +754,7 @@ namespace sol {
747754
}
748755
else {
749756
constexpr bool non_class_object_type = meta::any<std::is_void<object_type>,
750-
meta::boolean<lua_type_of<meta::unwrap_unqualified_t<object_type>>::value != type::userdata>>::value;
757+
meta::boolean<lua_type_of<meta::unwrap_unqualified_t<object_type>>::value != type::userdata>>::value;
751758
if constexpr (non_class_object_type) {
752759
// The type being void means we don't have any arguments, so it might be a free functions?
753760
using args_list = typename traits_type::free_args_list;
@@ -861,7 +868,8 @@ namespace sol {
861868
}
862869
}
863870

864-
template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls, bool clean_stack = true>
871+
template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls,
872+
bool clean_stack = true>
865873
inline int call_user(lua_State* L) {
866874
auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start));
867875
return call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);

include/sol/error_handler.hpp

Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// sol3
1+
// sol3
22

33
// The MIT License (MIT)
44

@@ -27,6 +27,8 @@
2727
#include "types.hpp"
2828
#include "demangle.hpp"
2929

30+
#include <cstdio>
31+
3032
namespace sol {
3133

3234
namespace detail {
@@ -46,21 +48,20 @@ namespace sol {
4648
constexpr const char* not_enough_stack_space_environment = "not enough space left on Lua stack to retrieve environment";
4749
constexpr const char* protected_function_error = "caught (...) unknown error during protected_function call";
4850

49-
inline void accumulate_and_mark(const std::string& n, std::string& addendum, int& marker) {
51+
inline void accumulate_and_mark(const std::string& n, std::string& aux_message, int& marker) {
5052
if (marker > 0) {
51-
addendum += ", ";
53+
aux_message += ", ";
5254
}
53-
addendum += n;
55+
aux_message += n;
5456
++marker;
5557
}
56-
}
58+
} // namespace detail
5759

5860
inline std::string associated_type_name(lua_State* L, int index, type t) {
5961
switch (t) {
6062
case type::poly:
6163
return "anything";
62-
case type::userdata:
63-
{
64+
case type::userdata: {
6465
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
6566
luaL_checkstack(L, 2, "not enough space to push get the type name");
6667
#endif // make sure stack doesn't overflow
@@ -81,63 +82,67 @@ namespace sol {
8182
return lua_typename(L, static_cast<int>(t));
8283
}
8384

84-
inline int type_panic_string(lua_State* L, int index, type expected, type actual, const std::string& message = "") noexcept(false) {
85-
const char* err = message.empty() ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s";
86-
std::string actualname = associated_type_name(L, index, actual);
87-
return luaL_error(L, err, index,
88-
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
89-
actualname.c_str(),
90-
message.c_str());
85+
inline int push_type_panic_string(lua_State* L, int index, type expected, type actual, string_view message, string_view aux_message) noexcept {
86+
const char* err = message.size() == 0
87+
? (aux_message.size() == 0 ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s")
88+
: "stack index %d, expected %s, received %s: %s %s";
89+
const char* type_name = expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected));
90+
{
91+
std::string actual_name = associated_type_name(L, index, actual);
92+
lua_pushfstring(L, err, index, type_name, actual_name.c_str(), message.data(), aux_message.data());
93+
}
94+
return 1;
95+
}
96+
97+
inline int type_panic_string(lua_State* L, int index, type expected, type actual, string_view message = "") noexcept(false) {
98+
push_type_panic_string(L, index, expected, actual, message, "");
99+
return lua_error(L);
91100
}
92101

93102
inline int type_panic_c_str(lua_State* L, int index, type expected, type actual, const char* message = nullptr) noexcept(false) {
94-
const char* err = message == nullptr || (std::char_traits<char>::length(message) == 0) ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s";
95-
std::string actualname = associated_type_name(L, index, actual);
96-
return luaL_error(L, err, index,
97-
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
98-
actualname.c_str(),
99-
message);
103+
push_type_panic_string(L, index, expected, actual, message == nullptr ? "" : message, "");
104+
return lua_error(L);
100105
}
101106

102107
struct type_panic_t {
103108
int operator()(lua_State* L, int index, type expected, type actual) const noexcept(false) {
104109
return type_panic_c_str(L, index, expected, actual, nullptr);
105110
}
106-
int operator()(lua_State* L, int index, type expected, type actual, const char* message) const noexcept(false) {
107-
return type_panic_c_str(L, index, expected, actual, message);
108-
}
109-
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
110-
return type_panic_string(L, index, expected, actual, message);
111+
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
112+
return type_panic_c_str(L, index, expected, actual, message.data());
111113
}
112114
};
113115

114116
const type_panic_t type_panic = {};
115117

116118
struct constructor_handler {
117-
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
118-
std::string str = "(type check failed in constructor)";
119-
return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str);
119+
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
120+
push_type_panic_string(L, index, expected, actual, message, "(type check failed in constructor)");
121+
return lua_error(L);
120122
}
121123
};
122124

123125
template <typename F = void>
124126
struct argument_handler {
125-
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
126-
std::string str = "(bad argument to variable or function call)";
127-
return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str );
127+
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
128+
push_type_panic_string(L, index, expected, actual, message, "(bad argument to variable or function call)");
129+
return lua_error(L);
128130
}
129131
};
130132

131133
template <typename R, typename... Args>
132134
struct argument_handler<types<R, Args...>> {
133-
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
134-
std::string addendum = "(bad argument into '";
135-
addendum += detail::demangle<R>();
136-
addendum += "(";
137-
int marker = 0;
138-
(void)detail::swallow{int(), (detail::accumulate_and_mark(detail::demangle<Args>(), addendum, marker), int())...};
139-
addendum += ")')";
140-
return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + " " + addendum);
135+
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
136+
{
137+
std::string aux_message = "(bad argument into '";
138+
aux_message += detail::demangle<R>();
139+
aux_message += "(";
140+
int marker = 0;
141+
(void)detail::swallow{ int(), (detail::accumulate_and_mark(detail::demangle<Args>(), aux_message, marker), int())... };
142+
aux_message += ")')";
143+
push_type_panic_string(L, index, expected, actual, message, aux_message);
144+
}
145+
return lua_error(L);
141146
}
142147
};
143148

include/sol/pointer_like.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ namespace sol {
7171
}
7272

7373
template <typename T>
74-
inline decltype(auto) deref_non_pointer(T&& item) {
74+
inline decltype(auto) deref_move_only(T&& item) {
7575
using Tu = meta::unqualified_t<T>;
76-
if constexpr (meta::is_pointer_like_v<Tu> && !std::is_pointer_v<Tu>) {
76+
if constexpr (meta::is_pointer_like_v<Tu> && !std::is_pointer_v<Tu> && !std::is_copy_constructible_v<Tu>) {
7777
return *std::forward<T>(item);
7878
}
7979
else {

0 commit comments

Comments
 (0)