aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto I <roberto@inf.puc-rio.br>2026-04-23 17:57:42 -0300
committerRoberto I <roberto@inf.puc-rio.br>2026-04-23 17:57:42 -0300
commit3228a97c6a953dcf397944161bb64b12f1ff5384 (patch)
tree6497f6f8e93ba3bb381c0b48aed71646fca3f9b0
parent0c16a42d61d08266033ff63bc5dfade6312b7359 (diff)
downloadlua-3228a97c6a953dcf397944161bb64b12f1ff5384.tar.gz
lua-3228a97c6a953dcf397944161bb64b12f1ff5384.tar.bz2
lua-3228a97c6a953dcf397944161bb64b12f1ff5384.zip
Bug: 'lua_load' does not preserve the stack
'lua_load' does not preserve the stack through the calls to the reader function, as it should. Immediately after the first call (to detect whether chunk is binary) it adds stuff, and it also adds a new table when starting the compilation of each new function.
-rw-r--r--ldo.c32
-rw-r--r--ldo.h1
-rw-r--r--lparser.c23
-rw-r--r--lparser.h5
-rw-r--r--lundump.c13
-rw-r--r--lundump.h4
-rw-r--r--testes/calls.lua26
7 files changed, 77 insertions, 27 deletions
diff --git a/ldo.c b/ldo.c
index 12e0364b..ec360ee8 100644
--- a/ldo.c
+++ b/ldo.c
@@ -1128,28 +1128,54 @@ static void checkmode (lua_State *L, const char *mode, const char *x) {
1128} 1128}
1129 1129
1130 1130
1131/*
1132** Before the first call to the reader function, Lua reserves a slot
1133** with a table for anchoring stuff.
1134*/
1131static void f_parser (lua_State *L, void *ud) { 1135static void f_parser (lua_State *L, void *ud) {
1132 LClosure *cl; 1136 LClosure *cl;
1133 struct SParser *p = cast(struct SParser *, ud); 1137 struct SParser *p = cast(struct SParser *, ud);
1134 const char *mode = p->mode ? p->mode : "bt"; 1138 const char *mode = p->mode ? p->mode : "bt";
1135 int c = zgetc(p->z); /* read first character */ 1139 int c;
1140 Table *anchor;
1141 ptrdiff_t otop = savestack(L, L->top.p); /* original top */
1142 luaD_checkstack(L, 2);
1143 anchor = luaH_new(L); /* create the anchor table */
1144 sethvalue2s(L, L->top.p++, anchor); /* anchor the anchor table */
1145 c = zgetc(p->z); /* read first character */
1136 if (c == LUA_SIGNATURE[0]) { 1146 if (c == LUA_SIGNATURE[0]) {
1137 int fixed = 0; 1147 int fixed = 0;
1138 if (strchr(mode, 'B') != NULL) 1148 if (strchr(mode, 'B') != NULL)
1139 fixed = 1; 1149 fixed = 1;
1140 else 1150 else
1141 checkmode(L, mode, "binary"); 1151 checkmode(L, mode, "binary");
1142 cl = luaU_undump(L, p->z, p->name, fixed); 1152 cl = luaU_undump(L, p->z, anchor, p->name, fixed);
1143 } 1153 }
1144 else { 1154 else {
1145 checkmode(L, mode, "text"); 1155 checkmode(L, mode, "text");
1146 cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); 1156 cl = luaY_parser(L, p->z, anchor, &p->buff, &p->dyd, p->name, c);
1147 } 1157 }
1158 L->top.p = restorestack(L, otop); /* restore stack */
1159 setclLvalue2s(L, L->top.p++, cl); /* push closure */
1148 lua_assert(cl->nupvalues == cl->p->sizeupvalues); 1160 lua_assert(cl->nupvalues == cl->p->sizeupvalues);
1149 luaF_initupvals(L, cl); 1161 luaF_initupvals(L, cl);
1150} 1162}
1151 1163
1152 1164
1165/*
1166** Anchor an object in a table in the stack. First, anchor the object
1167** temporarily in the stack, as luaH_set may call an emergency GC.
1168** Then, add it in the table with itself as its key.
1169*/
1170void luaD_anchorobj (lua_State *L, Table *anchor, GCObject *obj) {
1171 setgcovalue(L, s2v(L->top.p++), obj); /* temporary anchor in the stack */
1172 luaH_set(L, anchor, s2v(L->top.p - 1), s2v(L->top.p - 1));
1173 /* Because this is a new key, luaH_set will call the GC barrier, so
1174 we don't need to call the barrier again here */
1175 L->top.p--;
1176}
1177
1178
1153TStatus luaD_protectedparser (lua_State *L, ZIO *z, const char *name, 1179TStatus luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
1154 const char *mode) { 1180 const char *mode) {
1155 struct SParser p; 1181 struct SParser p;
diff --git a/ldo.h b/ldo.h
index b6472954..2b3b0db4 100644
--- a/ldo.h
+++ b/ldo.h
@@ -90,6 +90,7 @@ LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
90LUAI_FUNC void luaD_shrinkstack (lua_State *L); 90LUAI_FUNC void luaD_shrinkstack (lua_State *L);
91LUAI_FUNC void luaD_inctop (lua_State *L); 91LUAI_FUNC void luaD_inctop (lua_State *L);
92LUAI_FUNC int luaD_checkminstack (lua_State *L); 92LUAI_FUNC int luaD_checkminstack (lua_State *L);
93LUAI_FUNC void luaD_anchorobj (lua_State *L, Table *anchor, GCObject *obj);
93 94
94LUAI_FUNC l_noret luaD_throw (lua_State *L, TStatus errcode); 95LUAI_FUNC l_noret luaD_throw (lua_State *L, TStatus errcode);
95LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode); 96LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode);
diff --git a/lparser.c b/lparser.c
index 6b87773e..1850d6dc 100644
--- a/lparser.c
+++ b/lparser.c
@@ -821,8 +821,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
821 luaC_objbarrier(L, f, f->source); 821 luaC_objbarrier(L, f, f->source);
822 f->maxstacksize = 2; /* registers 0/1 are always valid */ 822 f->maxstacksize = 2; /* registers 0/1 are always valid */
823 fs->kcache = luaH_new(L); /* create table for function */ 823 fs->kcache = luaH_new(L); /* create table for function */
824 sethvalue2s(L, L->top.p, fs->kcache); /* anchor it */ 824 luaD_anchorobj(L, ls->h, obj2gco(fs->kcache)); /* anchor it */
825 luaD_inctop(L);
826 enterblock(fs, bl, 0); 825 enterblock(fs, bl, 0);
827} 826}
828 827
@@ -831,6 +830,7 @@ static void close_func (LexState *ls) {
831 lua_State *L = ls->L; 830 lua_State *L = ls->L;
832 FuncState *fs = ls->fs; 831 FuncState *fs = ls->fs;
833 Proto *f = fs->f; 832 Proto *f = fs->f;
833 TValue temp;
834 luaK_ret(fs, luaY_nvarstack(fs), 0); /* final return */ 834 luaK_ret(fs, luaY_nvarstack(fs), 0); /* final return */
835 leaveblock(fs); 835 leaveblock(fs);
836 lua_assert(fs->bl == NULL); 836 lua_assert(fs->bl == NULL);
@@ -843,8 +843,10 @@ static void close_func (LexState *ls) {
843 luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *); 843 luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *);
844 luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->ndebugvars, LocVar); 844 luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->ndebugvars, LocVar);
845 luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); 845 luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
846 /* remove kcache table from scanner table ("weigh" its anchor) */
847 sethvalue(L, &temp, fs->kcache); /* key to be set to nil */
848 luaH_set(L, ls->h, &temp, &G(L)->nilvalue);
846 ls->fs = fs->prev; 849 ls->fs = fs->prev;
847 L->top.p--; /* pop kcache table */
848 luaC_checkGC(L); 850 luaC_checkGC(L);
849} 851}
850 852
@@ -2174,16 +2176,14 @@ static void mainfunc (LexState *ls, FuncState *fs) {
2174} 2176}
2175 2177
2176 2178
2177LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, 2179LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor, Mbuffer *buff,
2178 Dyndata *dyd, const char *name, int firstchar) { 2180 Dyndata *dyd, const char *name, int firstchar) {
2179 LexState lexstate; 2181 LexState lexstate;
2180 FuncState funcstate; 2182 FuncState funcstate;
2181 LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ 2183 LClosure *cl;
2182 setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */ 2184 lexstate.h = anchor; /* table for scanner */
2183 luaD_inctop(L); 2185 cl = luaF_newLclosure(L, 1); /* create main closure */
2184 lexstate.h = luaH_new(L); /* create table for scanner */ 2186 luaD_anchorobj(L, anchor, obj2gco(cl)); /* anchor it in scanner table */
2185 sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
2186 luaD_inctop(L);
2187 funcstate.f = cl->p = luaF_newproto(L); 2187 funcstate.f = cl->p = luaF_newproto(L);
2188 luaC_objbarrier(L, cl, cl->p); 2188 luaC_objbarrier(L, cl, cl->p);
2189 funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ 2189 funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
@@ -2196,7 +2196,6 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
2196 lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); 2196 lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
2197 /* all scopes should be correctly finished */ 2197 /* all scopes should be correctly finished */
2198 lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); 2198 lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
2199 L->top.p--; /* remove scanner's table */ 2199 return cl;
2200 return cl; /* closure is on the stack, too */
2201} 2200}
2202 2201
diff --git a/lparser.h b/lparser.h
index a30df04f..4fad6bdc 100644
--- a/lparser.h
+++ b/lparser.h
@@ -189,8 +189,9 @@ typedef struct FuncState {
189LUAI_FUNC lu_byte luaY_nvarstack (FuncState *fs); 189LUAI_FUNC lu_byte luaY_nvarstack (FuncState *fs);
190LUAI_FUNC void luaY_checklimit (FuncState *fs, int v, int l, 190LUAI_FUNC void luaY_checklimit (FuncState *fs, int v, int l,
191 const char *what); 191 const char *what);
192LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, 192LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor,
193 Dyndata *dyd, const char *name, int firstchar); 193 Mbuffer *buff, Dyndata *dyd,
194 const char *name, int firstchar);
194 195
195 196
196#endif 197#endif
diff --git a/lundump.c b/lundump.c
index 3b61cc8c..d5fdc64b 100644
--- a/lundump.c
+++ b/lundump.c
@@ -392,7 +392,8 @@ static void checkHeader (LoadState *S) {
392/* 392/*
393** Load precompiled chunk. 393** Load precompiled chunk.
394*/ 394*/
395LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) { 395LClosure *luaU_undump (lua_State *L, ZIO *Z, Table *anchor, const char *name,
396 int fixed) {
396 LoadState S; 397 LoadState S;
397 LClosure *cl; 398 LClosure *cl;
398 if (*name == '@' || *name == '=') 399 if (*name == '@' || *name == '=')
@@ -405,20 +406,16 @@ LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) {
405 S.fixed = cast_byte(fixed); 406 S.fixed = cast_byte(fixed);
406 S.offset = 1; /* fist byte was already read */ 407 S.offset = 1; /* fist byte was already read */
407 checkHeader(&S); 408 checkHeader(&S);
408 cl = luaF_newLclosure(L, loadByte(&S)); 409 S.h = anchor;
409 setclLvalue2s(L, L->top.p, cl);
410 luaD_inctop(L);
411 S.h = luaH_new(L); /* create list of saved strings */
412 S.nstr = 0; 410 S.nstr = 0;
413 sethvalue2s(L, L->top.p, S.h); /* anchor it */ 411 cl = luaF_newLclosure(L, loadByte(&S));
414 luaD_inctop(L); 412 luaD_anchorobj(L, anchor, obj2gco(cl));
415 cl->p = luaF_newproto(L); 413 cl->p = luaF_newproto(L);
416 luaC_objbarrier(L, cl, cl->p); 414 luaC_objbarrier(L, cl, cl->p);
417 loadFunction(&S, cl->p); 415 loadFunction(&S, cl->p);
418 if (cl->nupvalues != cl->p->sizeupvalues) 416 if (cl->nupvalues != cl->p->sizeupvalues)
419 error(&S, "corrupted chunk"); 417 error(&S, "corrupted chunk");
420 luai_verifycode(L, cl->p); 418 luai_verifycode(L, cl->p);
421 L->top.p--; /* pop table */
422 return cl; 419 return cl;
423} 420}
424 421
diff --git a/lundump.h b/lundump.h
index c4e06f9e..186e25f8 100644
--- a/lundump.h
+++ b/lundump.h
@@ -30,8 +30,8 @@
30 30
31 31
32/* load one chunk; from lundump.c */ 32/* load one chunk; from lundump.c */
33LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name, 33LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Table *anchor,
34 int fixed); 34 const char* name, int fixed);
35 35
36/* dump one chunk; from ldump.c */ 36/* dump one chunk; from ldump.c */
37LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, 37LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
diff --git a/testes/calls.lua b/testes/calls.lua
index 0dacb85a..cd4510a2 100644
--- a/testes/calls.lua
+++ b/testes/calls.lua
@@ -372,6 +372,32 @@ do -- another bug (in 5.4.0)
372end 372end
373 373
374 374
375if T then
376 -- check stack level when calling reader function
377 local function get (str)
378 local pos = 0
379 local level = nil
380 return function ()
381 pos = pos + 1
382 local c = string.sub(str, pos, pos)
383 local newlevel = T.stacklevel()
384 if not level then
385 level = newlevel
386 else
387 assert(level == newlevel)
388 end
389 return #c > 0 and c or nil
390 end
391 end
392
393 local str = "local function foo () end; return 121"
394 assert(assert(load(get(str)))() == 121)
395
396 str = string.dump(load(str))
397 assert(assert(load(get(str)))() == 121)
398end
399
400
375x = string.dump(load("x = 1; return x")) 401x = string.dump(load("x = 1; return x"))
376a = assert(load(read1(x), nil, "b")) 402a = assert(load(read1(x), nil, "b"))
377assert(a() == 1 and _G.x == 1) 403assert(a() == 1 and _G.x == 1)