Restore state when recording __concat metamethod throws OOM.

Reported by Sergey Kaplun. #1298 #1234
This commit is contained in:
Mike Pall 2024-11-28 18:07:58 +01:00
parent 35a4dd6f79
commit 19878ec05c

View File

@ -2080,25 +2080,19 @@ static TRef rec_tnew(jit_State *J, uint32_t ah)
typedef struct RecCatDataCP { typedef struct RecCatDataCP {
jit_State *J; jit_State *J;
RecordIndex *ix; BCReg baseslot, topslot;
TRef tr;
} RecCatDataCP; } RecCatDataCP;
static TValue *rec_mm_concat_cp(lua_State *L, lua_CFunction dummy, void *ud) static TValue *rec_mm_concat_cp(lua_State *L, lua_CFunction dummy, void *ud)
{ {
RecCatDataCP *rcd = (RecCatDataCP *)ud; RecCatDataCP *rcd = (RecCatDataCP *)ud;
UNUSED(L); UNUSED(dummy); jit_State *J = rcd->J;
rec_mm_arith(rcd->J, rcd->ix, MM_concat); /* Call __concat metamethod. */ BCReg baseslot = rcd->baseslot, topslot = rcd->topslot;
return NULL;
}
static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot)
{
TRef *top = &J->base[topslot]; TRef *top = &J->base[topslot];
TValue savetv[5+LJ_FR2];
BCReg s; BCReg s;
RecordIndex ix; RecordIndex ix;
RecCatDataCP rcd; UNUSED(L); UNUSED(dummy);
int errcode;
lj_assertJ(baseslot < topslot, "bad CAT arg"); lj_assertJ(baseslot < topslot, "bad CAT arg");
for (s = baseslot; s <= topslot; s++) for (s = baseslot; s <= topslot; s++)
(void)getslot(J, s); /* Ensure all arguments have a reference. */ (void)getslot(J, s); /* Ensure all arguments have a reference. */
@ -2120,7 +2114,10 @@ static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot)
} while (trp <= top); } while (trp <= top);
tr = emitir(IRTG(IR_BUFSTR, IRT_STR), tr, hdr); tr = emitir(IRTG(IR_BUFSTR, IRT_STR), tr, hdr);
J->maxslot = (BCReg)(xbase - J->base); J->maxslot = (BCReg)(xbase - J->base);
if (xbase == base) return tr; /* Return simple concatenation result. */ if (xbase == base) {
rcd->tr = tr; /* Return simple concatenation result. */
return NULL;
}
/* Pass partial result. */ /* Pass partial result. */
topslot = J->maxslot--; topslot = J->maxslot--;
*xbase = tr; *xbase = tr;
@ -2133,13 +2130,31 @@ static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot)
copyTV(J->L, &ix.tabv, &J->L->base[topslot-1]); copyTV(J->L, &ix.tabv, &J->L->base[topslot-1]);
ix.tab = top[-1]; ix.tab = top[-1];
ix.key = top[0]; ix.key = top[0];
memcpy(savetv, &J->L->base[topslot-1], sizeof(savetv)); /* Save slots. */ rec_mm_arith(J, &ix, MM_concat); /* Call __concat metamethod. */
rcd->tr = 0; /* No result yet. */
return NULL;
}
static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot)
{
lua_State *L = J->L;
ptrdiff_t delta = L->top - L->base;
TValue savetv[5+LJ_FR2], errobj;
RecCatDataCP rcd;
int errcode;
rcd.J = J; rcd.J = J;
rcd.ix = &ix; rcd.baseslot = baseslot;
errcode = lj_vm_cpcall(J->L, NULL, &rcd, rec_mm_concat_cp); rcd.topslot = topslot;
memcpy(&J->L->base[topslot-1], savetv, sizeof(savetv)); /* Restore slots. */ memcpy(savetv, &L->base[topslot-1], sizeof(savetv)); /* Save slots. */
if (errcode) return (TRef)(-errcode); errcode = lj_vm_cpcall(L, NULL, &rcd, rec_mm_concat_cp);
return 0; /* No result yet. */ if (errcode) copyTV(L, &errobj, L->top-1);
memcpy(&L->base[topslot-1], savetv, sizeof(savetv)); /* Restore slots. */
if (errcode) {
L->top = L->base + delta;
copyTV(L, L->top++, &errobj);
return (TRef)(-errcode);
}
return rcd.tr;
} }
/* -- Record bytecode ops ------------------------------------------------- */ /* -- Record bytecode ops ------------------------------------------------- */