diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-17 10:42:49 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-17 10:42:49 +0200 |
commit | d359e8cf7d71c2f80a1706fef38e603478ac003f (patch) | |
tree | 8f9562d595ab9d43496fee998b0825b330294b59 /src | |
parent | 38a4b6b252dd46dc00e1871886e35c196ed1f245 (diff) | |
download | lanes-d359e8cf7d71c2f80a1706fef38e603478ac003f.tar.gz lanes-d359e8cf7d71c2f80a1706fef38e603478ac003f.tar.bz2 lanes-d359e8cf7d71c2f80a1706fef38e603478ac003f.zip |
Fix bad assert when raising a non-string error
Diffstat (limited to 'src')
-rw-r--r-- | src/lane.cpp | 93 |
1 files changed, 54 insertions, 39 deletions
diff --git a/src/lane.cpp b/src/lane.cpp index 7165e85..f320071 100644 --- a/src/lane.cpp +++ b/src/lane.cpp | |||
@@ -43,7 +43,7 @@ THE SOFTWARE. | |||
43 | // ######################################### Lua API ############################################### | 43 | // ######################################### Lua API ############################################### |
44 | // ################################################################################################# | 44 | // ################################################################################################# |
45 | 45 | ||
46 | LUAG_FUNC(get_debug_threadname) | 46 | static LUAG_FUNC(get_debug_threadname) |
47 | { | 47 | { |
48 | Lane* const _lane{ ToLane(L_, 1) }; | 48 | Lane* const _lane{ ToLane(L_, 1) }; |
49 | luaL_argcheck(L_, lua_gettop(L_) == 1, 2, "too many arguments"); | 49 | luaL_argcheck(L_, lua_gettop(L_) == 1, 2, "too many arguments"); |
@@ -60,7 +60,7 @@ LUAG_FUNC(get_debug_threadname) | |||
60 | // Add a function that will be called when exiting the lane, either via | 60 | // Add a function that will be called when exiting the lane, either via |
61 | // normal return or an error. | 61 | // normal return or an error. |
62 | // | 62 | // |
63 | LUAG_FUNC(set_finalizer) | 63 | static LUAG_FUNC(set_finalizer) |
64 | { | 64 | { |
65 | luaL_argcheck(L_, lua_isfunction(L_, 1), 1, "finalizer should be a function"); | 65 | luaL_argcheck(L_, lua_isfunction(L_, 1), 1, "finalizer should be a function"); |
66 | luaL_argcheck(L_, lua_gettop(L_) == 1, 1, "too many arguments"); | 66 | luaL_argcheck(L_, lua_gettop(L_) == 1, 1, "too many arguments"); |
@@ -98,7 +98,7 @@ LUAG_FUNC(set_error_reporting) | |||
98 | // ################################################################################################# | 98 | // ################################################################################################# |
99 | 99 | ||
100 | // upvalue #1 is the lane userdata | 100 | // upvalue #1 is the lane userdata |
101 | LUAG_FUNC(set_debug_threadname) | 101 | static LUAG_FUNC(set_debug_threadname) |
102 | { | 102 | { |
103 | // C s_lane structure is a light userdata upvalue | 103 | // C s_lane structure is a light userdata upvalue |
104 | Lane* const _lane{ lua_tolightuserdata<Lane>(L_, lua_upvalueindex(1)) }; | 104 | Lane* const _lane{ lua_tolightuserdata<Lane>(L_, lua_upvalueindex(1)) }; |
@@ -120,10 +120,9 @@ LUAG_FUNC(set_debug_threadname) | |||
120 | // error: returns nil + error value [+ stack table] | 120 | // error: returns nil + error value [+ stack table] |
121 | // cancelled: returns nil | 121 | // cancelled: returns nil |
122 | // | 122 | // |
123 | LUAG_FUNC(thread_join) | 123 | static LUAG_FUNC(thread_join) |
124 | { | 124 | { |
125 | Lane* const _lane{ ToLane(L_, 1) }; | 125 | Lane* const _lane{ ToLane(L_, 1) }; |
126 | lua_State* const _L2{ _lane->L }; | ||
127 | 126 | ||
128 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; | 127 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; |
129 | if (lua_type(L_, 2) == LUA_TNUMBER) { // we don't want to use lua_isnumber() because of autocoercion | 128 | if (lua_type(L_, 2) == LUA_TNUMBER) { // we don't want to use lua_isnumber() because of autocoercion |
@@ -138,9 +137,10 @@ LUAG_FUNC(thread_join) | |||
138 | raise_luaL_argerror(L_, 2, "incorrect duration type"); | 137 | raise_luaL_argerror(L_, 2, "incorrect duration type"); |
139 | } | 138 | } |
140 | 139 | ||
141 | bool const done{ !_lane->thread.joinable() || _lane->waitForCompletion(_until) }; | 140 | bool const _done{ !_lane->thread.joinable() || _lane->waitForCompletion(_until) }; |
142 | lua_settop(L_, 1); // L_: lane | 141 | lua_settop(L_, 1); // L_: lane |
143 | if (!done || !_L2) { | 142 | lua_State* const _L2{ _lane->L }; |
143 | if (!_done || !_L2) { | ||
144 | lua_pushnil(L_); // L_: lane nil | 144 | lua_pushnil(L_); // L_: lane nil |
145 | lua_pushliteral(L_, "timeout"); // L_: lane nil "timeout" | 145 | lua_pushliteral(L_, "timeout"); // L_: lane nil "timeout" |
146 | return 2; | 146 | return 2; |
@@ -484,17 +484,18 @@ static void push_stack_trace(lua_State* L_, LuaError rc_, int stk_base_) | |||
484 | // For other errors, the message can be whatever was thrown, and we should have a stack trace table | 484 | // For other errors, the message can be whatever was thrown, and we should have a stack trace table |
485 | LUA_ASSERT(L_, lua_type(L_, 1 + stk_base_) == (kCancelError.equals(L_, stk_base_) ? LUA_TNIL : LUA_TTABLE)); | 485 | LUA_ASSERT(L_, lua_type(L_, 1 + stk_base_) == (kCancelError.equals(L_, stk_base_) ? LUA_TNIL : LUA_TTABLE)); |
486 | // Just leaving the stack trace table on the stack is enough to get it through to the master. | 486 | // Just leaving the stack trace table on the stack is enough to get it through to the master. |
487 | break; | ||
488 | } | 487 | } |
489 | #else // !ERROR_FULL_STACK | 488 | #else // !ERROR_FULL_STACK |
490 | [[fallthrough]]; // fall through if not ERROR_FULL_STACK | 489 | // any kind of error can be thrown with error(), or through a lane/linda cancellation |
490 | LUA_ASSERT(L_, lua_gettop(L_) == stk_base_); | ||
491 | #endif // !ERROR_FULL_STACK | 491 | #endif // !ERROR_FULL_STACK |
492 | break; | ||
492 | 493 | ||
493 | case LuaError::ERRMEM: // memory allocation error (handler not called) | 494 | case LuaError::ERRMEM: // memory allocation error (handler not called) |
494 | case LuaError::ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) | 495 | case LuaError::ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) |
495 | default: | 496 | default: |
496 | // we should have a single value which is either a string (the error message) or kCancelError | 497 | // the Lua core provides a string error message in those situations |
497 | LUA_ASSERT(L_, (lua_gettop(L_) == stk_base_) && ((lua_type(L_, stk_base_) == LUA_TSTRING) || kCancelError.equals(L_, stk_base_))); | 498 | LUA_ASSERT(L_, (lua_gettop(L_) == stk_base_) && (lua_type(L_, stk_base_) == LUA_TSTRING)); |
498 | break; | 499 | break; |
499 | } | 500 | } |
500 | } | 501 | } |
@@ -621,6 +622,28 @@ static void selfdestruct_add(Lane* lane_) | |||
621 | // ########################################## Main ################################################# | 622 | // ########################################## Main ################################################# |
622 | // ################################################################################################# | 623 | // ################################################################################################# |
623 | 624 | ||
625 | static void PrepareLaneHelpers(Lane* lane_) | ||
626 | { | ||
627 | lua_State* const _L{ lane_->L }; | ||
628 | // Tie "set_finalizer()" to the state | ||
629 | lua_pushcfunction(_L, LG_set_finalizer); | ||
630 | populate_func_lookup_table(_L, -1, "set_finalizer"); | ||
631 | lua_setglobal(_L, "set_finalizer"); | ||
632 | |||
633 | // Tie "set_debug_threadname()" to the state | ||
634 | // But don't register it in the lookup database because of the Lane pointer upvalue | ||
635 | lua_pushlightuserdata(_L, lane_); | ||
636 | lua_pushcclosure(_L, LG_set_debug_threadname, 1); | ||
637 | lua_setglobal(_L, "set_debug_threadname"); | ||
638 | |||
639 | // Tie "cancel_test()" to the state | ||
640 | lua_pushcfunction(_L, LG_cancel_test); | ||
641 | populate_func_lookup_table(_L, -1, "cancel_test"); | ||
642 | lua_setglobal(_L, "cancel_test"); | ||
643 | } | ||
644 | |||
645 | // ################################################################################################# | ||
646 | |||
624 | static void lane_main(Lane* lane_) | 647 | static void lane_main(Lane* lane_) |
625 | { | 648 | { |
626 | lua_State* const _L{ lane_->L }; | 649 | lua_State* const _L{ lane_->L }; |
@@ -629,25 +652,11 @@ static void lane_main(Lane* lane_) | |||
629 | LuaError _rc{ LuaError::ERRRUN }; | 652 | LuaError _rc{ LuaError::ERRRUN }; |
630 | if (lane_->status == Lane::Pending) { // nothing wrong happened during preparation, we can work | 653 | if (lane_->status == Lane::Pending) { // nothing wrong happened during preparation, we can work |
631 | // At this point, the lane function and arguments are on the stack | 654 | // At this point, the lane function and arguments are on the stack |
632 | int const nargs{ lua_gettop(_L) - 1 }; | 655 | int const _nargs{ lua_gettop(_L) - 1 }; |
633 | DEBUGSPEW_CODE(Universe* _U = universe_get(_L)); | 656 | DEBUGSPEW_CODE(Universe* _U = universe_get(_L)); |
634 | lane_->status = Lane::Running; // Pending -> Running | 657 | lane_->status = Lane::Running; // Pending -> Running |
635 | 658 | ||
636 | // Tie "set_finalizer()" to the state | 659 | PrepareLaneHelpers(lane_); |
637 | lua_pushcfunction(_L, LG_set_finalizer); | ||
638 | populate_func_lookup_table(_L, -1, "set_finalizer"); | ||
639 | lua_setglobal(_L, "set_finalizer"); | ||
640 | |||
641 | // Tie "set_debug_threadname()" to the state | ||
642 | // But don't register it in the lookup database because of the Lane pointer upvalue | ||
643 | lua_pushlightuserdata(_L, lane_); | ||
644 | lua_pushcclosure(_L, LG_set_debug_threadname, 1); | ||
645 | lua_setglobal(_L, "set_debug_threadname"); | ||
646 | |||
647 | // Tie "cancel_test()" to the state | ||
648 | lua_pushcfunction(_L, LG_cancel_test); | ||
649 | populate_func_lookup_table(_L, -1, "cancel_test"); | ||
650 | lua_setglobal(_L, "cancel_test"); | ||
651 | 660 | ||
652 | // this could be done in lane_new before the lane body function is pushed on the stack to avoid unnecessary stack slot shifting around | 661 | // this could be done in lane_new before the lane body function is pushed on the stack to avoid unnecessary stack slot shifting around |
653 | #if ERROR_FULL_STACK | 662 | #if ERROR_FULL_STACK |
@@ -661,7 +670,7 @@ static void lane_main(Lane* lane_) | |||
661 | lua_insert(_L, 1); // L: handler func args | 670 | lua_insert(_L, 1); // L: handler func args |
662 | #endif // L: ERROR_FULL_STACK | 671 | #endif // L: ERROR_FULL_STACK |
663 | 672 | ||
664 | _rc = ToLuaError(lua_pcall(_L, nargs, LUA_MULTRET, ERROR_FULL_STACK)); // L: retvals|err | 673 | _rc = ToLuaError(lua_pcall(_L, _nargs, LUA_MULTRET, ERROR_FULL_STACK)); // L: retvals|err |
665 | 674 | ||
666 | #if ERROR_FULL_STACK | 675 | #if ERROR_FULL_STACK |
667 | lua_remove(_L, 1); // L: retvals|error | 676 | lua_remove(_L, 1); // L: retvals|error |
@@ -813,29 +822,35 @@ void Lane::changeDebugName(int nameIdx_) | |||
813 | 822 | ||
814 | // ################################################################################################# | 823 | // ################################################################################################# |
815 | 824 | ||
816 | // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname } | 825 | namespace global { |
826 | static struct luaL_Reg const sLaneFunctions[] = { | ||
827 | { "__gc", lane_gc }, | ||
828 | { "__index", LG_thread_index }, | ||
829 | { "cancel", LG_thread_cancel }, | ||
830 | { "get_debug_threadname", LG_get_debug_threadname }, | ||
831 | { "join", LG_thread_join }, | ||
832 | { nullptr, nullptr } | ||
833 | }; | ||
834 | } // namespace global | ||
835 | |||
836 | // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname } | ||
817 | void Lane::PushMetatable(lua_State* L_) | 837 | void Lane::PushMetatable(lua_State* L_) |
818 | { | 838 | { |
839 | STACK_CHECK_START_REL(L_, 0); | ||
819 | if (luaL_newmetatable(L_, kLaneMetatableName)) { // L_: mt | 840 | if (luaL_newmetatable(L_, kLaneMetatableName)) { // L_: mt |
820 | lua_pushcfunction(L_, lane_gc); // L_: mt lane_gc | 841 | luaG_registerlibfuncs(L_, global::sLaneFunctions); |
821 | lua_setfield(L_, -2, "__gc"); // L_: mt | 842 | // cache error() and tostring() |
822 | lua_pushcfunction(L_, LG_thread_index); // L_: mt LG_thread_index | ||
823 | lua_setfield(L_, -2, "__index"); // L_: mt | ||
824 | lua_getglobal(L_, "error"); // L_: mt error | 843 | lua_getglobal(L_, "error"); // L_: mt error |
825 | LUA_ASSERT(L_, lua_isfunction(L_, -1)); | 844 | LUA_ASSERT(L_, lua_isfunction(L_, -1)); |
826 | lua_setfield(L_, -2, "cached_error"); // L_: mt | 845 | lua_setfield(L_, -2, "cached_error"); // L_: mt |
827 | lua_getglobal(L_, "tostring"); // L_: mt tostring | 846 | lua_getglobal(L_, "tostring"); // L_: mt tostring |
828 | LUA_ASSERT(L_, lua_isfunction(L_, -1)); | 847 | LUA_ASSERT(L_, lua_isfunction(L_, -1)); |
829 | lua_setfield(L_, -2, "cached_tostring"); // L_: mt | 848 | lua_setfield(L_, -2, "cached_tostring"); // L_: mt |
830 | lua_pushcfunction(L_, LG_thread_join); // L_: mt LG_thread_join | 849 | // hide the actual metatable from getmetatable() |
831 | lua_setfield(L_, -2, "join"); // L_: mt | ||
832 | lua_pushcfunction(L_, LG_get_debug_threadname); // L_: mt LG_get_debug_threadname | ||
833 | lua_setfield(L_, -2, "get_debug_threadname"); // L_: mt | ||
834 | lua_pushcfunction(L_, LG_thread_cancel); // L_: mt LG_thread_cancel | ||
835 | lua_setfield(L_, -2, "cancel"); // L_: mt | ||
836 | lua_pushliteral(L_, kLaneMetatableName); // L_: mt "Lane" | 850 | lua_pushliteral(L_, kLaneMetatableName); // L_: mt "Lane" |
837 | lua_setfield(L_, -2, "__metatable"); // L_: mt | 851 | lua_setfield(L_, -2, "__metatable"); // L_: mt |
838 | } | 852 | } |
853 | STACK_CHECK(L_, 1); | ||
839 | } | 854 | } |
840 | // ################################################################################################# | 855 | // ################################################################################################# |
841 | 856 | ||