Fix memory deallocation while yielding in redbean.

The yielded coroutine was removed from the stack too early,
leaving it not being anchored, which led to memory freed prematurely.
This commit is contained in:
Paul Kulchenko 2022-04-14 07:36:29 -07:00
parent fb7e8ef1e6
commit 3d997ccb35
3 changed files with 6 additions and 4 deletions

View file

@ -42,7 +42,10 @@ int LuaCallWithTrace(lua_State *L, int nargs, int nres, lua_State *C) {
lua_xmove(L, C, 1 + nargs);
// resume the coroutine thus executing the function
status = lua_resume(C, L, nargs, &nresults);
lua_remove(L, 1); // remove coroutine (still) at the bottom
// remove coroutine (still) at the bottom, but only if not yielding
// keep it when yielding to anchor, so it's not GC-collected
// it's going to be removed at the beggining of the request handling
if (!canyield) lua_remove(L, 1);
if (status != LUA_OK && status != LUA_YIELD) {
// move the error message
lua_xmove(C, L, 1);

View file

@ -13,7 +13,6 @@ COSMOPOLITAN_C_START_
char *s = LuaFormatStack(L); \
WARNF("lua stack should be empty!\n%s", s); \
free(s); \
lua_settop(L, 0); \
} \
} while (0)

View file

@ -2406,6 +2406,7 @@ static int LuaCallWithYield(lua_State *L) {
// the second set of headers is not going to be sent
lua_State *co = lua_newthread(L);
if ((status = LuaCallWithTrace(L, 0, 0, co)) == LUA_YIELD) {
CHECK_GT(lua_gettop(L), 0); // make sure that coroutine is anchored
YL = co;
generator = YieldGenerator;
if (!isyielding) isyielding = 1;
@ -3002,9 +3003,9 @@ static char *LuaOnHttpRequest(void) {
lua_State *L = GL;
effectivepath.p = url.path.p;
effectivepath.n = url.path.n;
lua_settop(L, 0); // clear Lua stack, as it needs to start fresh
lua_getglobal(L, "OnHttpRequest");
if (LuaCallWithYield(L) == LUA_OK) {
AssertLuaStackIsEmpty(L);
return CommitOutput(GetLuaResponse());
} else {
LogLuaError("OnHttpRequest", lua_tostring(L, -1));
@ -3012,7 +3013,6 @@ static char *LuaOnHttpRequest(void) {
500, "Internal Server Error",
ShouldServeCrashReportDetails() ? lua_tostring(L, -1) : NULL);
lua_pop(L, 1); // pop error
AssertLuaStackIsEmpty(L);
return error;
}
}