add coroutine guard

update version
add donation link
This commit is contained in:
ThePhD 2017-11-21 14:33:27 -05:00
parent 4256c07ee0
commit a0de11a773
10 changed files with 137 additions and 15 deletions

View File

@ -85,6 +85,12 @@ Please make sure you use the `-std=c++1y`, `-std=c++14`, `-std=c++1z`, `-std=c++
Older compilers (GCC 4.9.x, Clang 3.4.x seem to be the lowest) can work with versions as late
as [v2.17.5](https://github.com/ThePhD/sol2/releases/tag/v2.17.5), with the flag `-std=c++14` or `-std=c++1y`.
## Supporting
You can help out the library by submitting pull requests to fix anything or add anything you think would be helpful! This includes making small, useful examples of something you haven't seen, or fixing typos and bad code in the documentation.
You can also [donate to support me and my family](paypal.me/LMeneide), which is always appreciated!
## License
Sol is distributed with an MIT License. You can see LICENSE.txt for more info.

View File

@ -61,7 +61,7 @@ author = 'ThePhD'
# The short X.Y version.
version = '2.18'
# The full version, including alpha/beta/rc tags.
release = '2.18.6'
release = '2.18.7'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@ -114,6 +114,15 @@ the basics:
}
helping out
-----------
You can support the library by submitting pull requests to fix anything (the code, typos, even contribute your own examples).
You can support me and my family by `donating a little something here`_.
Thank you for using sol2!
Indices and tables
==================
@ -123,4 +132,5 @@ Indices and tables
.. _Sol: https://github.com/ThePhD/sol2
.. _issues: https://github.com/ThePhD/sol2/issues
.. _examples directory: https://github.com/ThePhD/sol2/tree/develop/examples
.. _examples directory: https://github.com/ThePhD/sol2/tree/develop/examples
.. _donating a little something here: paypal.me/LMeneide

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2017-11-17 21:50:58.352644 UTC
// This header was generated with sol v2.18.6 (revision 4a39020)
// Generated 2017-11-21 19:13:27.385503 UTC
// This header was generated with sol v2.18.6 (revision 4256c07)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -247,6 +247,7 @@ namespace sol {
using main_object = basic_object<main_reference>;
using main_userdata = basic_userdata<main_reference>;
using main_lightuserdata = basic_lightuserdata<main_reference>;
using main_coroutine = basic_coroutine<main_reference>;
using stack_object = basic_object<stack_reference>;
using stack_userdata = basic_userdata<stack_reference>;
using stack_lightuserdata = basic_lightuserdata<stack_reference>;
@ -5784,21 +5785,23 @@ namespace sol {
struct constructor_handler {
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
return type_panic_string(L, index, expected, actual, message + " (type check failed in constructor)");
std::string str = "(type check failed in constructor)";
return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str);
}
};
template <typename F = void>
struct argument_handler {
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
return type_panic_string(L, index, expected, actual, message + " (bad argument to variable or function call)");
std::string str = "(bad argument to variable or function call)";
return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str );
}
};
template <typename R, typename... Args>
struct argument_handler<types<R, Args...>> {
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
std::string addendum = " (bad argument into '";
std::string addendum = "(bad argument into '";
addendum += detail::demangle<R>();
addendum += "(";
int marker = 0;
@ -5811,7 +5814,7 @@ namespace sol {
};
(void)detail::swallow{int(), (action(detail::demangle<Args>()), int())...};
addendum += ")')";
return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + addendum);
return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + " " + addendum);
}
};
@ -7065,6 +7068,28 @@ namespace sol {
return lua_gettop(L);
}
inline bool is_main_thread(lua_State* L) {
int ismainthread = lua_pushthread(L);
lua_pop(L, 1);
return ismainthread == 1;
}
inline void coroutine_create_guard(lua_State* L) {
if (is_main_thread(L)) {
return;
}
int stacksize = lua_gettop(L);
if (stacksize < 1) {
return;
}
if (type_of(L, 1) != type::function) {
return;
}
// well now we're screwed...
// we can clean the stack and pray it doesn't destroy anything?
lua_pop(L, stacksize);
}
template <typename T, typename... Args>
inline int push(lua_State* L, T&& t, Args&&... args) {
return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
@ -19373,6 +19398,12 @@ namespace sol {
return stack::top(L);
}
int stack_clear() {
int s = stack_top();
lua_pop(L, s);
return s;
}
void collect_garbage() {
lua_gc(lua_state(), LUA_GCCOLLECT, 0);
}
@ -19704,9 +19735,7 @@ namespace sol {
}
bool is_main_thread() const {
int ismainthread = lua_pushthread(this->thread_state());
lua_pop(this->thread_state(), 1);
return ismainthread == 1;
return stack::is_main_thread(this->thread_state());
}
lua_State* thread_state() const {
@ -19941,6 +19970,11 @@ namespace sol {
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
// some users screw up coroutine.create
// and try to use it with sol::coroutine without ever calling the first resume in Lua
// this makes the stack incompatible with other kinds of stacks: protect against this
// make sure coroutines don't screw us over
stack::coroutine_create_guard(lua_state());
base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);

View File

@ -142,6 +142,11 @@ namespace sol {
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
// some users screw up coroutine.create
// and try to use it with sol::coroutine without ever calling the first resume in Lua
// this makes the stack incompatible with other kinds of stacks: protect against this
// make sure coroutines don't screw us over
stack::coroutine_create_guard(lua_state());
base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);

View File

@ -120,6 +120,7 @@ namespace sol {
using main_object = basic_object<main_reference>;
using main_userdata = basic_userdata<main_reference>;
using main_lightuserdata = basic_lightuserdata<main_reference>;
using main_coroutine = basic_coroutine<main_reference>;
using stack_object = basic_object<stack_reference>;
using stack_userdata = basic_userdata<stack_reference>;
using stack_lightuserdata = basic_lightuserdata<stack_reference>;

View File

@ -568,6 +568,28 @@ namespace sol {
return lua_gettop(L);
}
inline bool is_main_thread(lua_State* L) {
int ismainthread = lua_pushthread(L);
lua_pop(L, 1);
return ismainthread == 1;
}
inline void coroutine_create_guard(lua_State* L) {
if (is_main_thread(L)) {
return;
}
int stacksize = lua_gettop(L);
if (stacksize < 1) {
return;
}
if (type_of(L, 1) != type::function) {
return;
}
// well now we're screwed...
// we can clean the stack and pray it doesn't destroy anything?
lua_pop(L, stacksize);
}
template <typename T, typename... Args>
inline int push(lua_State* L, T&& t, Args&&... args) {
return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);

View File

@ -524,6 +524,12 @@ namespace sol {
return stack::top(L);
}
int stack_clear() {
int s = stack_top();
lua_pop(L, s);
return s;
}
void collect_garbage() {
lua_gc(lua_state(), LUA_GCCOLLECT, 0);
}

View File

@ -160,9 +160,7 @@ namespace sol {
}
bool is_main_thread() const {
int ismainthread = lua_pushthread(this->thread_state());
lua_pop(this->thread_state(), 1);
return ismainthread == 1;
return stack::is_main_thread(this->thread_state());
}
lua_State* thread_state() const {

View File

@ -4,7 +4,7 @@
#include <catch.hpp>
#include <sol.hpp>
TEST_CASE("coroutines/threading", "ensure calling a coroutine works") {
TEST_CASE("coroutines/yielding", "ensure calling a coroutine works") {
const auto& script = R"(counter = 20
function loop()
@ -363,3 +363,43 @@ collectgarbage()
std::string s = t[1];
REQUIRE(s == "SOME_TABLE");
}
TEST_CASE("coroutines/coroutine.create protection", "ensure that a thread picked up from coroutine.create does not throw off the lua stack entirely when called from C++") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script(
R"(
function loop()
local i = 0
while true do
print("pre-yield in loop")
coroutine.yield(i)
print("post-yield in loop")
i = i+1
end
end
loop_th = coroutine.create(loop)
)"
);
sol::thread runner_thread = lua["loop_th"];
auto test_resume = [&runner_thread]() {
sol::state_view th_state = runner_thread.state();
sol::coroutine cr = th_state["loop"];
int r = cr();
return r;
};
lua.set_function("test_resume", std::ref(test_resume));
int v0 = test_resume();
int v1 = test_resume();
int v2 = lua.script("return test_resume()");
int v3 = lua.script("return test_resume()");
REQUIRE(v0 == 0);
REQUIRE(v1 == 1);
REQUIRE(v2 == 2);
REQUIRE(v3 == 3);
}