Skip to content

Commit 422ce50

Browse files
committed
Fixed detail in 'loadUpvalues'
In 'lundump.c', when loading the upvalues of a function, there can be a read error if the chunk is truncated. In that case, the creation of the error message can trigger an emergency collection while the prototype is still anchored. So, the prototype must be GC consistent before loading the upvales, which implies that it the 'name' fields must be filled with NULL before the reading.
1 parent c33b172 commit 422ce50

File tree

3 files changed

+24
-7
lines changed

3 files changed

+24
-7
lines changed

lapi.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
563563
while (n--) {
564564
setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
565565
/* does not need barrier because closure is white */
566+
lua_assert(iswhite(cl));
566567
}
567568
setclCvalue(L, s2v(L->top), cl);
568569
api_incr_top(L);

lundump.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,20 @@ static void loadProtos (LoadState *S, Proto *f) {
200200
}
201201

202202

203+
/*
204+
** Load the upvalues for a function. The names must be filled first,
205+
** because the filling of the other fields can raise read errors and
206+
** the creation of the error message can call an emergency collection;
207+
** in that case all prototypes must be consistent for the GC.
208+
*/
203209
static void loadUpvalues (LoadState *S, Proto *f) {
204210
int i, n;
205211
n = loadInt(S);
206212
f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
207213
f->sizeupvalues = n;
208-
for (i = 0; i < n; i++) {
214+
for (i = 0; i < n; i++) /* make array valid for GC */
209215
f->upvalues[i].name = NULL;
216+
for (i = 0; i < n; i++) { /* following calls can raise errors */
210217
f->upvalues[i].instack = loadByte(S);
211218
f->upvalues[i].idx = loadByte(S);
212219
f->upvalues[i].kind = loadByte(S);

testes/calls.lua

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -422,20 +422,30 @@ assert((function (a) return a end)() == nil)
422422

423423
print("testing binary chunks")
424424
do
425-
local header = string.pack("c4BBc6BBBj",
425+
local header = string.pack("c4BBc6BBB",
426426
"\27Lua", -- signature
427427
0x54, -- version 5.4 (0x54)
428428
0, -- format
429429
"\x19\x93\r\n\x1a\n", -- data
430430
4, -- size of instruction
431431
string.packsize("j"), -- sizeof(lua integer)
432-
string.packsize("n"), -- sizeof(lua number)
433-
0x5678 -- LUAC_INT
434-
-- LUAC_NUM may not have a unique binary representation (padding...)
432+
string.packsize("n") -- sizeof(lua number)
435433
)
436-
local c = string.dump(function () local a = 1; local b = 3; return a+b*3 end)
434+
local c = string.dump(function ()
435+
local a = 1; local b = 3;
436+
local f = function () return a + b + _ENV.c; end -- upvalues
437+
local s1 = "a constant"
438+
local s2 = "another constant"
439+
return a + b * 3
440+
end)
437441

442+
assert(assert(load(c))() == 10)
443+
444+
-- check header
438445
assert(string.sub(c, 1, #header) == header)
446+
-- check LUAC_INT and LUAC_NUM
447+
local ci, cn = string.unpack("jn", c, #header + 1)
448+
assert(ci == 0x5678 and cn == 370.5)
439449

440450
-- corrupted header
441451
for i = 1, #header do
@@ -451,7 +461,6 @@ do
451461
local st, msg = load(string.sub(c, 1, i))
452462
assert(not st and string.find(msg, "truncated"))
453463
end
454-
assert(assert(load(c))() == 10)
455464
end
456465

457466
print('OK')

0 commit comments

Comments
 (0)