diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-13 13:11:09 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-13 13:11:09 -0300 |
| commit | eabf425c76e0089eb88e102e2a44d8c8a37bc213 (patch) | |
| tree | 7ad9e9901cbab5f2852187c16560ec74d21a0921 | |
| parent | 3b57e37e4821ddce4756428956b7e9f4969efa4c (diff) | |
| download | lua-eabf425c76e0089eb88e102e2a44d8c8a37bc213.tar.gz lua-eabf425c76e0089eb88e102e2a44d8c8a37bc213.tar.bz2 lua-eabf425c76e0089eb88e102e2a44d8c8a37bc213.zip | |
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.
| -rw-r--r-- | ldump.c | 7 | ||||
| -rw-r--r-- | lundump.c | 72 |
2 files changed, 37 insertions, 42 deletions
| @@ -144,7 +144,7 @@ static void dumpCode (DumpState *D, const Proto *f) { | |||
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | 146 | ||
| 147 | static void dumpFunction(DumpState *D, const Proto *f); | 147 | static void dumpFunction (DumpState *D, const Proto *f); |
| 148 | 148 | ||
| 149 | static void dumpConstants (DumpState *D, const Proto *f) { | 149 | static void dumpConstants (DumpState *D, const Proto *f) { |
| 150 | int i; | 150 | int i; |
| @@ -218,10 +218,6 @@ static void dumpDebug (DumpState *D, const Proto *f) { | |||
| 218 | 218 | ||
| 219 | 219 | ||
| 220 | static void dumpFunction (DumpState *D, const Proto *f) { | 220 | static void dumpFunction (DumpState *D, const Proto *f) { |
| 221 | if (D->strip) | ||
| 222 | dumpString(D, NULL); /* no debug info */ | ||
| 223 | else | ||
| 224 | dumpString(D, f->source); | ||
| 225 | dumpInt(D, f->linedefined); | 221 | dumpInt(D, f->linedefined); |
| 226 | dumpInt(D, f->lastlinedefined); | 222 | dumpInt(D, f->lastlinedefined); |
| 227 | dumpByte(D, f->numparams); | 223 | dumpByte(D, f->numparams); |
| @@ -231,6 +227,7 @@ static void dumpFunction (DumpState *D, const Proto *f) { | |||
| 231 | dumpConstants(D, f); | 227 | dumpConstants(D, f); |
| 232 | dumpUpvalues(D, f); | 228 | dumpUpvalues(D, f); |
| 233 | dumpProtos(D, f); | 229 | dumpProtos(D, f); |
| 230 | dumpString(D, D->strip ? NULL : f->source); | ||
| 234 | dumpDebug(D, f); | 231 | dumpDebug(D, f); |
| 235 | } | 232 | } |
| 236 | 233 | ||
| @@ -132,57 +132,49 @@ static lua_Integer loadInteger (LoadState *S) { | |||
| 132 | 132 | ||
| 133 | 133 | ||
| 134 | /* | 134 | /* |
| 135 | ** Load a nullable string into prototype 'p'. | 135 | ** Load a nullable string into slot 'sl' from prototype 'p'. The |
| 136 | ** assignment to the slot and the barrier must be performed before any | ||
| 137 | ** possible GC activity, to anchor the string. (Both 'loadVector' and | ||
| 138 | ** 'luaH_setint' can call the GC.) | ||
| 136 | */ | 139 | */ |
| 137 | static TString *loadStringN (LoadState *S, Proto *p) { | 140 | static void loadString (LoadState *S, Proto *p, TString **sl) { |
| 138 | lua_State *L = S->L; | 141 | lua_State *L = S->L; |
| 139 | TString *ts; | 142 | TString *ts; |
| 140 | TValue sv; | 143 | TValue sv; |
| 141 | size_t size = loadSize(S); | 144 | size_t size = loadSize(S); |
| 142 | if (size == 0) /* no string? */ | 145 | if (size == 0) { /* no string? */ |
| 143 | return NULL; | 146 | *sl = NULL; |
| 147 | return; | ||
| 148 | } | ||
| 144 | else if (size == 1) { /* previously saved string? */ | 149 | else if (size == 1) { /* previously saved string? */ |
| 145 | int idx = loadInt(S); /* get its index */ | 150 | int idx = loadInt(S); /* get its index */ |
| 146 | TValue stv; | 151 | TValue stv; |
| 147 | luaH_getint(S->h, idx, &stv); | 152 | luaH_getint(S->h, idx, &stv); |
| 148 | return tsvalue(&stv); | 153 | *sl = ts = tsvalue(&stv); |
| 154 | luaC_objbarrier(L, p, ts); | ||
| 155 | return; | ||
| 149 | } | 156 | } |
| 150 | else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */ | 157 | else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */ |
| 151 | char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */ | 158 | char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */ |
| 152 | loadVector(S, buff, size + 1); /* load string into buffer */ | 159 | loadVector(S, buff, size + 1); /* load string into buffer */ |
| 153 | ts = luaS_newlstr(L, buff, size); /* create string */ | 160 | *sl = ts = luaS_newlstr(L, buff, size); /* create string */ |
| 161 | luaC_objbarrier(L, p, ts); | ||
| 154 | } | 162 | } |
| 155 | else { /* long string */ | 163 | else if (S->fixed) { /* for a fixed buffer, use a fixed string */ |
| 156 | if (S->fixed) { /* for a fixed buffer, use a fixed string */ | 164 | const char *s = getaddr(S, size + 1, char); /* get content address */ |
| 157 | const char *s = getaddr(S, size + 1, char); /* get content address */ | 165 | *sl = ts = luaS_newextlstr(L, s, size, NULL, NULL); |
| 158 | ts = luaS_newextlstr(L, s, size, NULL, NULL); | 166 | luaC_objbarrier(L, p, ts); |
| 159 | } | 167 | } |
| 160 | else { /* create internal copy */ | 168 | else { /* create internal copy */ |
| 161 | ts = luaS_createlngstrobj(L, size); /* create string */ | 169 | *sl = ts = luaS_createlngstrobj(L, size); /* create string */ |
| 162 | setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */ | 170 | luaC_objbarrier(L, p, ts); |
| 163 | luaD_inctop(L); | 171 | loadVector(S, getlngstr(ts), size); /* load directly in final place */ |
| 164 | loadVector(S, getlngstr(ts), size); /* load directly in final place */ | 172 | loadByte(S); /* skip ending '\0' */ |
| 165 | loadByte(S); /* skip ending '\0' */ | ||
| 166 | L->top.p--; /* pop string */ | ||
| 167 | } | ||
| 168 | } | 173 | } |
| 169 | luaC_objbarrier(L, p, ts); | ||
| 170 | S->nstr++; /* add string to list of saved strings */ | 174 | S->nstr++; /* add string to list of saved strings */ |
| 171 | setsvalue(L, &sv, ts); | 175 | setsvalue(L, &sv, ts); |
| 172 | luaH_setint(L, S->h, S->nstr, &sv); | 176 | luaH_setint(L, S->h, S->nstr, &sv); |
| 173 | luaC_objbarrierback(L, obj2gco(S->h), ts); | 177 | luaC_objbarrierback(L, obj2gco(S->h), ts); |
| 174 | return ts; | ||
| 175 | } | ||
| 176 | |||
| 177 | |||
| 178 | /* | ||
| 179 | ** Load a non-nullable string into prototype 'p'. | ||
| 180 | */ | ||
| 181 | static TString *loadString (LoadState *S, Proto *p) { | ||
| 182 | TString *st = loadStringN(S, p); | ||
| 183 | if (st == NULL) | ||
| 184 | error(S, "bad format for constant string"); | ||
| 185 | return st; | ||
| 186 | } | 178 | } |
| 187 | 179 | ||
| 188 | 180 | ||
| @@ -231,9 +223,15 @@ static void loadConstants (LoadState *S, Proto *f) { | |||
| 231 | setivalue(o, loadInteger(S)); | 223 | setivalue(o, loadInteger(S)); |
| 232 | break; | 224 | break; |
| 233 | case LUA_VSHRSTR: | 225 | case LUA_VSHRSTR: |
| 234 | case LUA_VLNGSTR: | 226 | case LUA_VLNGSTR: { |
| 235 | setsvalue2n(S->L, o, loadString(S, f)); | 227 | lua_assert(f->source == NULL); |
| 228 | loadString(S, f, &f->source); /* use 'source' to anchor string */ | ||
| 229 | if (f->source == NULL) | ||
| 230 | error(S, "bad format for constant string"); | ||
| 231 | setsvalue2n(S->L, o, f->source); /* save it in the right place */ | ||
| 232 | f->source = NULL; | ||
| 236 | break; | 233 | break; |
| 234 | } | ||
| 237 | default: lua_assert(0); | 235 | default: lua_assert(0); |
| 238 | } | 236 | } |
| 239 | } | 237 | } |
| @@ -301,7 +299,7 @@ static void loadDebug (LoadState *S, Proto *f) { | |||
| 301 | for (i = 0; i < n; i++) | 299 | for (i = 0; i < n; i++) |
| 302 | f->locvars[i].varname = NULL; | 300 | f->locvars[i].varname = NULL; |
| 303 | for (i = 0; i < n; i++) { | 301 | for (i = 0; i < n; i++) { |
| 304 | f->locvars[i].varname = loadStringN(S, f); | 302 | loadString(S, f, &f->locvars[i].varname); |
| 305 | f->locvars[i].startpc = loadInt(S); | 303 | f->locvars[i].startpc = loadInt(S); |
| 306 | f->locvars[i].endpc = loadInt(S); | 304 | f->locvars[i].endpc = loadInt(S); |
| 307 | } | 305 | } |
| @@ -309,12 +307,11 @@ static void loadDebug (LoadState *S, Proto *f) { | |||
| 309 | if (n != 0) /* does it have debug information? */ | 307 | if (n != 0) /* does it have debug information? */ |
| 310 | n = f->sizeupvalues; /* must be this many */ | 308 | n = f->sizeupvalues; /* must be this many */ |
| 311 | for (i = 0; i < n; i++) | 309 | for (i = 0; i < n; i++) |
| 312 | f->upvalues[i].name = loadStringN(S, f); | 310 | loadString(S, f, &f->upvalues[i].name); |
| 313 | } | 311 | } |
| 314 | 312 | ||
| 315 | 313 | ||
| 316 | static void loadFunction (LoadState *S, Proto *f) { | 314 | static void loadFunction (LoadState *S, Proto *f) { |
| 317 | f->source = loadStringN(S, f); | ||
| 318 | f->linedefined = loadInt(S); | 315 | f->linedefined = loadInt(S); |
| 319 | f->lastlinedefined = loadInt(S); | 316 | f->lastlinedefined = loadInt(S); |
| 320 | f->numparams = loadByte(S); | 317 | f->numparams = loadByte(S); |
| @@ -326,6 +323,7 @@ static void loadFunction (LoadState *S, Proto *f) { | |||
| 326 | loadConstants(S, f); | 323 | loadConstants(S, f); |
| 327 | loadUpvalues(S, f); | 324 | loadUpvalues(S, f); |
| 328 | loadProtos(S, f); | 325 | loadProtos(S, f); |
| 326 | loadString(S, f, &f->source); | ||
| 329 | loadDebug(S, f); | 327 | loadDebug(S, f); |
| 330 | } | 328 | } |
| 331 | 329 | ||
