Correct anchoring and GC barriers in 'loadString'

Call to 'luaH_setint' could call the GC with the string unanchored.
Moreover, previously saved strings were being assigned to the prototype
without a barrier.
This commit is contained in:
Roberto Ierusalimschy
2023-11-13 13:11:09 -03:00
parent 3b57e37e48
commit eabf425c76
2 changed files with 37 additions and 42 deletions

View File

@@ -144,7 +144,7 @@ static void dumpCode (DumpState *D, const Proto *f) {
} }
static void dumpFunction(DumpState *D, const Proto *f); static void dumpFunction (DumpState *D, const Proto *f);
static void dumpConstants (DumpState *D, const Proto *f) { static void dumpConstants (DumpState *D, const Proto *f) {
int i; int i;
@@ -218,10 +218,6 @@ static void dumpDebug (DumpState *D, const Proto *f) {
static void dumpFunction (DumpState *D, const Proto *f) { static void dumpFunction (DumpState *D, const Proto *f) {
if (D->strip)
dumpString(D, NULL); /* no debug info */
else
dumpString(D, f->source);
dumpInt(D, f->linedefined); dumpInt(D, f->linedefined);
dumpInt(D, f->lastlinedefined); dumpInt(D, f->lastlinedefined);
dumpByte(D, f->numparams); dumpByte(D, f->numparams);
@@ -231,6 +227,7 @@ static void dumpFunction (DumpState *D, const Proto *f) {
dumpConstants(D, f); dumpConstants(D, f);
dumpUpvalues(D, f); dumpUpvalues(D, f);
dumpProtos(D, f); dumpProtos(D, f);
dumpString(D, D->strip ? NULL : f->source);
dumpDebug(D, f); dumpDebug(D, f);
} }

View File

@@ -132,57 +132,49 @@ static lua_Integer loadInteger (LoadState *S) {
/* /*
** Load a nullable string into prototype 'p'. ** Load a nullable string into slot 'sl' from prototype 'p'. The
** assignment to the slot and the barrier must be performed before any
** possible GC activity, to anchor the string. (Both 'loadVector' and
** 'luaH_setint' can call the GC.)
*/ */
static TString *loadStringN (LoadState *S, Proto *p) { static void loadString (LoadState *S, Proto *p, TString **sl) {
lua_State *L = S->L; lua_State *L = S->L;
TString *ts; TString *ts;
TValue sv; TValue sv;
size_t size = loadSize(S); size_t size = loadSize(S);
if (size == 0) /* no string? */ if (size == 0) { /* no string? */
return NULL; *sl = NULL;
return;
}
else if (size == 1) { /* previously saved string? */ else if (size == 1) { /* previously saved string? */
int idx = loadInt(S); /* get its index */ int idx = loadInt(S); /* get its index */
TValue stv; TValue stv;
luaH_getint(S->h, idx, &stv); luaH_getint(S->h, idx, &stv);
return tsvalue(&stv); *sl = ts = tsvalue(&stv);
luaC_objbarrier(L, p, ts);
return;
} }
else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */ else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */
char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */ char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */
loadVector(S, buff, size + 1); /* load string into buffer */ loadVector(S, buff, size + 1); /* load string into buffer */
ts = luaS_newlstr(L, buff, size); /* create string */ *sl = ts = luaS_newlstr(L, buff, size); /* create string */
luaC_objbarrier(L, p, ts);
} }
else { /* long string */ else if (S->fixed) { /* for a fixed buffer, use a fixed string */
if (S->fixed) { /* for a fixed buffer, use a fixed string */
const char *s = getaddr(S, size + 1, char); /* get content address */ const char *s = getaddr(S, size + 1, char); /* get content address */
ts = luaS_newextlstr(L, s, size, NULL, NULL); *sl = ts = luaS_newextlstr(L, s, size, NULL, NULL);
luaC_objbarrier(L, p, ts);
} }
else { /* create internal copy */ else { /* create internal copy */
ts = luaS_createlngstrobj(L, size); /* create string */ *sl = ts = luaS_createlngstrobj(L, size); /* create string */
setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */ luaC_objbarrier(L, p, ts);
luaD_inctop(L);
loadVector(S, getlngstr(ts), size); /* load directly in final place */ loadVector(S, getlngstr(ts), size); /* load directly in final place */
loadByte(S); /* skip ending '\0' */ loadByte(S); /* skip ending '\0' */
L->top.p--; /* pop string */
} }
}
luaC_objbarrier(L, p, ts);
S->nstr++; /* add string to list of saved strings */ S->nstr++; /* add string to list of saved strings */
setsvalue(L, &sv, ts); setsvalue(L, &sv, ts);
luaH_setint(L, S->h, S->nstr, &sv); luaH_setint(L, S->h, S->nstr, &sv);
luaC_objbarrierback(L, obj2gco(S->h), ts); luaC_objbarrierback(L, obj2gco(S->h), ts);
return ts;
}
/*
** Load a non-nullable string into prototype 'p'.
*/
static TString *loadString (LoadState *S, Proto *p) {
TString *st = loadStringN(S, p);
if (st == NULL)
error(S, "bad format for constant string");
return st;
} }
@@ -231,9 +223,15 @@ static void loadConstants (LoadState *S, Proto *f) {
setivalue(o, loadInteger(S)); setivalue(o, loadInteger(S));
break; break;
case LUA_VSHRSTR: case LUA_VSHRSTR:
case LUA_VLNGSTR: case LUA_VLNGSTR: {
setsvalue2n(S->L, o, loadString(S, f)); lua_assert(f->source == NULL);
loadString(S, f, &f->source); /* use 'source' to anchor string */
if (f->source == NULL)
error(S, "bad format for constant string");
setsvalue2n(S->L, o, f->source); /* save it in the right place */
f->source = NULL;
break; break;
}
default: lua_assert(0); default: lua_assert(0);
} }
} }
@@ -301,7 +299,7 @@ static void loadDebug (LoadState *S, Proto *f) {
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
f->locvars[i].varname = NULL; f->locvars[i].varname = NULL;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
f->locvars[i].varname = loadStringN(S, f); loadString(S, f, &f->locvars[i].varname);
f->locvars[i].startpc = loadInt(S); f->locvars[i].startpc = loadInt(S);
f->locvars[i].endpc = loadInt(S); f->locvars[i].endpc = loadInt(S);
} }
@@ -309,12 +307,11 @@ static void loadDebug (LoadState *S, Proto *f) {
if (n != 0) /* does it have debug information? */ if (n != 0) /* does it have debug information? */
n = f->sizeupvalues; /* must be this many */ n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f); loadString(S, f, &f->upvalues[i].name);
} }
static void loadFunction (LoadState *S, Proto *f) { static void loadFunction (LoadState *S, Proto *f) {
f->source = loadStringN(S, f);
f->linedefined = loadInt(S); f->linedefined = loadInt(S);
f->lastlinedefined = loadInt(S); f->lastlinedefined = loadInt(S);
f->numparams = loadByte(S); f->numparams = loadByte(S);
@@ -326,6 +323,7 @@ static void loadFunction (LoadState *S, Proto *f) {
loadConstants(S, f); loadConstants(S, f);
loadUpvalues(S, f); loadUpvalues(S, f);
loadProtos(S, f); loadProtos(S, f);
loadString(S, f, &f->source);
loadDebug(S, f); loadDebug(S, f);
} }