Use after free in 'luaV_finishset'
If a metatable is a weak table, its __newindex field could be collected by an emergency collection while being used in 'luaV_finishset'. (This bug has similarities with bug 5.3.2-1, fixed in commit a272fa66.)
This commit is contained in:
5
lapi.c
5
lapi.c
@@ -681,6 +681,11 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following function assumes that the registry cannot be a weak
|
||||||
|
** table, so that en mergency collection while using the global table
|
||||||
|
** cannot collect it.
|
||||||
|
*/
|
||||||
static void getGlobalTable (lua_State *L, TValue *gt) {
|
static void getGlobalTable (lua_State *L, TValue *gt) {
|
||||||
Table *registry = hvalue(&G(L)->l_registry);
|
Table *registry = hvalue(&G(L)->l_registry);
|
||||||
lu_byte tag = luaH_getint(registry, LUA_RIDX_GLOBALS, gt);
|
lu_byte tag = luaH_getint(registry, LUA_RIDX_GLOBALS, gt);
|
||||||
|
|||||||
8
lvm.c
8
lvm.c
@@ -325,6 +325,11 @@ lu_byte luaV_finishget (lua_State *L, const TValue *t, TValue *key,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Finish a table assignment 't[key] = val'.
|
** Finish a table assignment 't[key] = val'.
|
||||||
|
** About anchoring the table before the call to 'luaH_finishset':
|
||||||
|
** This call may trigger an emergency collection. When loop>0,
|
||||||
|
** the table being acessed is a field in some metatable. If this
|
||||||
|
** metatable is weak and the table is not anchored, this collection
|
||||||
|
** could collect that table while it is being updated.
|
||||||
*/
|
*/
|
||||||
void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
||||||
TValue *val, int hres) {
|
TValue *val, int hres) {
|
||||||
@@ -335,7 +340,10 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
|||||||
Table *h = hvalue(t); /* save 't' table */
|
Table *h = hvalue(t); /* save 't' table */
|
||||||
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
|
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
|
||||||
if (tm == NULL) { /* no metamethod? */
|
if (tm == NULL) { /* no metamethod? */
|
||||||
|
sethvalue2s(L, L->top.p, h); /* anchor 't' */
|
||||||
|
L->top.p++; /* assume EXTRA_STACK */
|
||||||
luaH_finishset(L, h, key, val, hres); /* set new value */
|
luaH_finishset(L, h, key, val, hres); /* set new value */
|
||||||
|
L->top.p--;
|
||||||
invalidateTMcache(h);
|
invalidateTMcache(h);
|
||||||
luaC_barrierback(L, obj2gco(h), val);
|
luaC_barrierback(L, obj2gco(h), val);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -379,6 +379,17 @@ x = 0 .."a".."b"..c..d.."e".."f".."g"
|
|||||||
assert(x.val == "0abcdefg")
|
assert(x.val == "0abcdefg")
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
-- bug since 5.4.1 (test needs T)
|
||||||
|
local mt = setmetatable({__newindex={}}, {__mode='v'})
|
||||||
|
local t = setmetatable({}, mt)
|
||||||
|
|
||||||
|
if T then T.allocfailnext() end
|
||||||
|
|
||||||
|
-- seg. fault
|
||||||
|
for i=1, 10 do t[i] = 1 end
|
||||||
|
end
|
||||||
|
|
||||||
-- concat metamethod x numbers (bug in 5.1.1)
|
-- concat metamethod x numbers (bug in 5.1.1)
|
||||||
c = {}
|
c = {}
|
||||||
local x
|
local x
|
||||||
@@ -481,7 +492,7 @@ assert(not pcall(function (a,b) return a[b] end, a, 10))
|
|||||||
assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true))
|
assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true))
|
||||||
|
|
||||||
-- bug in 5.1
|
-- bug in 5.1
|
||||||
T, K, V = nil
|
local T, K, V = nil
|
||||||
grandparent = {}
|
grandparent = {}
|
||||||
grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end
|
grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user