From 9c3d431b21e16025f12a305f67412e00a6b0ada1 Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Sun, 8 Nov 2026 11:44:31 +0200
Subject: [PATCH 69/69] Apply patch 4 for lua-5.5.1

See RM #2415

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 dependencies/lua-5.5/Version.txt    |  2 +-
 dependencies/lua-5.5/src/lcorolib.c |  3 ++-
 dependencies/lua-5.5/src/lstate.c   | 22 ++++++++++++++++++++--
 3 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/dependencies/lua-5.5/Version.txt b/dependencies/lua-5.5/Version.txt
index bcf9d9a4c0..9829116abc 100644
--- a/dependencies/lua-5.5/Version.txt
+++ b/dependencies/lua-5.5/Version.txt
@@ -2,7 +2,7 @@ Sources here are from lua-5.5.1
 (http://www.lua.org/ftp/lua-5.5.1.tar.gz)
 
 Upstream bug fixes from https://www.lua.org/bugs.html applied:
-1, 2, 3
+1, 2, 3, 4
 
 Not entire lua distribution directory hierarchy is included here, and
 some files needed for Freeciv usage have been added.
diff --git a/dependencies/lua-5.5/src/lcorolib.c b/dependencies/lua-5.5/src/lcorolib.c
index eb30bf4da5..976ac6386c 100644
--- a/dependencies/lua-5.5/src/lcorolib.c
+++ b/dependencies/lua-5.5/src/lcorolib.c
@@ -78,7 +78,8 @@ static int luaB_auxwrap (lua_State *L) {
     int stat = lua_status(co);
     if (stat != LUA_OK && stat != LUA_YIELD) {  /* error in the coroutine? */
       stat = lua_closethread(co, L);  /* close its tbc variables */
-      lua_assert(stat != LUA_OK);
+      if (stat == LUA_OK)
+        return 0;  /* nothing to return */
       lua_xmove(co, L, 1);  /* move error message to the caller */
     }
     if (stat != LUA_ERRMEM &&  /* not a memory error and ... */
diff --git a/dependencies/lua-5.5/src/lstate.c b/dependencies/lua-5.5/src/lstate.c
index ada0b8566a..08179357e6 100644
--- a/dependencies/lua-5.5/src/lstate.c
+++ b/dependencies/lua-5.5/src/lstate.c
@@ -319,18 +319,36 @@ TStatus luaE_resetthread (lua_State *L, TStatus status) {
   status = luaD_closeprotected(L, 1, status);
   if (status != LUA_OK)  /* errors? */
     luaD_seterrorobj(L, status, L->stack.p + 1);
-  else
+  else  /* keep in the stack only the fake function-entry for basic ci */
     L->top.p = L->stack.p + 1;
   luaD_reallocstack(L, cast_int(L->ci->top.p - L->stack.p), 0);
   return status;
 }
 
 
+/*
+** Auxiliary function to call luaE_resetthread in protected mode.
+** That function closes all tbc variables in protected mode, so the
+** only possible "error" is when a tbc variable closes the thread being
+** closed and therefore calls 'luaD_throwbaselevel'; in that case,
+** control goes directly back to the first call to lua_closethread (not
+** to the second), to properly return it.
+*/
+static void resetthread_aux (lua_State *L, void *ud) {
+  TStatus status = *cast(TStatus*, ud);
+  status = luaE_resetthread(L, status);
+  if (status != LUA_OK)
+    luaD_throw(L, status);
+}
+
+
 LUA_API int lua_closethread (lua_State *L, lua_State *from) {
   TStatus status;
   lua_lock(L);
   L->nCcalls = (from) ? getCcalls(from) : 0;
-  status = luaE_resetthread(L, L->status);
+  status = luaD_rawrunprotected(L, resetthread_aux, &L->status);
+  /* stack has error message iff there was an error */
+  lua_assert(L->top.p == L->stack.p + (status == LUA_OK ? 1 : 2));
   if (L == from)  /* closing itself? */
     luaD_throwbaselevel(L, status);
   lua_unlock(L);
-- 
2.53.0

