Hello.
Sometimes when calling collectgarbage() inside a coroutine, my application crashes with 'C Stack Overflow'. I managed to track it down to a negative number being assigned to nCcalls in lstate.c and ldo.c, so nCcalls becomes ~65534.
The temporary patch I use to fix this problem:
diff --git a/src/ldo.c b/src/ldo.c
index f2f9062..969a088 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -135,7 +135,8 @@ l_noret luaD_throw (lua_State *L, int errcode) {
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
- unsigned short oldnCcalls = L->nCcalls - L->nci;
+ unsigned short oldnCcalls = L->nCcalls;
+ unsigned short oldnci = L->nci;
struct lua_longjmp lj;
lj.status = LUA_OK;
lj.previous = L->errorJmp; /* chain new error handler */
@@ -144,7 +145,9 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
(*f)(L, ud);
);
L->errorJmp = lj.previous; /* restore old error handler */
- L->nCcalls = oldnCcalls + L->nci;
+ L->nCcalls = oldnCcalls;
+ if (L->nCcalls - (oldnci - L->nci) >= 0)
+ L->nCcalls -= oldnci - L->nci;
return lj.status;
}
diff --git a/src/lstate.c b/src/lstate.c
index a2cc4d9..3342635 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -135,13 +135,13 @@ void luaE_freeCI (lua_State *L) {
CallInfo *ci = L->ci;
CallInfo *next = ci->next;
ci->next = NULL;
- L->nCcalls -= L->nci; /* to subtract removed elements from 'nCcalls' */
while ((ci = next) != NULL) {
next = ci->next;
luaM_free(L, ci);
L->nci--;
+ if (L->nCcalls > 0)
+ L->nCcalls--; /* to subtract removed elements from 'nCcalls' */
}
- L->nCcalls += L->nci; /* to subtract removed elements from 'nCcalls' */
}
@@ -151,16 +150,16 @@ void luaE_freeCI (lua_State *L) {
void luaE_shrinkCI (lua_State *L) {
CallInfo *ci = L->ci;
CallInfo *next2; /* next's next */
- L->nCcalls -= L->nci; /* to subtract removed elements from 'nCcalls' */
/* while there are two nexts */
while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
luaM_free(L, ci->next); /* free next */
L->nci--;
+ if (L->nCcalls > 0)
+ L->nCcalls--; /* to subtract removed elements from 'nCcalls' */
ci->next = next2; /* remove 'next' from the list */
next2->previous = ci;
ci = next2; /* keep next's next */
}
- L->nCcalls += L->nci; /* to subtract removed elements from 'nCcalls' */
}