Skip to content

Commit 046129d

Browse files
author
Mike Pall
committed
Fix rechaining of pseudo-resurrected string keys.
This is a serious bug. But extremely hard to reproduce, so it went undetected for 8 years. One needs two resurrections with different main nodes, which are both in a hash chain which gets relinked on key insertion where the colliding node is in a non-main position. Phew. Thanks to lbeiming.
1 parent 03cd5aa commit 046129d

File tree

1 file changed

+23
-0
lines changed

1 file changed

+23
-0
lines changed

src/lj_tab.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,29 @@ TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key)
457457
freenode->next = nn->next;
458458
nn->next = n->next;
459459
setmref(n->next, nn);
460+
/*
461+
** Rechaining a resurrected string key creates a new dilemma:
462+
** Another string key may have originally been resurrected via
463+
** _any_ of the previous nodes as a chain anchor. Including
464+
** a node that had to be moved, which makes them unreachable.
465+
** It's not feasible to check for all previous nodes, so rechain
466+
** any string key that's currently in a non-main positions.
467+
*/
468+
while ((nn = nextnode(freenode))) {
469+
if (tvisstr(&nn->key) && !tvisnil(&nn->val)) {
470+
Node *mn = hashstr(t, strV(&nn->key));
471+
if (mn != freenode) {
472+
freenode->next = nn->next;
473+
nn->next = mn->next;
474+
setmref(mn->next, nn);
475+
} else {
476+
freenode = nn;
477+
}
478+
} else {
479+
freenode = nn;
480+
}
481+
}
482+
break;
460483
} else {
461484
freenode = nn;
462485
}

0 commit comments

Comments
 (0)