Fix memory deallocation while yielding in redbean. (#384)

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 18:13:53 -07:00 committed by GitHub
parent fb7e8ef1e6
commit 233144b19d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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;
}
}