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:
5
ldump.c
5
ldump.c
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
62
lundump.c
62
lundump.c
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user