Fixed bug of keys removed from tables vs 'next'

Fixed the bug that a key removed from a table might not be found
again by 'next'. (This is needed to allow keys to be removed during a
traversal.) This bug was introduced in commit 73ec04fc.
This commit is contained in:
Roberto Ierusalimschy
2020-10-14 15:46:58 -03:00
parent 849b2ecbd2
commit 52c8679760
4 changed files with 66 additions and 26 deletions

View File

@@ -172,11 +172,17 @@ static Node *mainpositionTV (const Table *t, const TValue *key) {
** be equal to floats. It is assumed that 'eqshrstr' is simply
** pointer equality, so that short strings are handled in the
** default case.
** A true 'deadok' means to accept dead keys as equal to their original
** values, which can only happen if the original key was collectable.
** All dead values are compared in the default case, by pointer
** identity. (Note that dead long strings are also compared by
** identity).
*/
static int equalkey (const TValue *k1, const Node *n2) {
if (rawtt(k1) != keytt(n2)) /* not the same variants? */
static int equalkey (const TValue *k1, const Node *n2, int deadok) {
if ((rawtt(k1) != keytt(n2)) && /* not the same variants? */
!(deadok && keyisdead(n2) && iscollectable(k1)))
return 0; /* cannot be same key */
switch (ttypetag(k1)) {
switch (keytt(n2)) {
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
return 1;
case LUA_VNUMINT:
@@ -187,7 +193,7 @@ static int equalkey (const TValue *k1, const Node *n2) {
return pvalue(k1) == pvalueraw(keyval(n2));
case LUA_VLCF:
return fvalue(k1) == fvalueraw(keyval(n2));
case LUA_VLNGSTR:
case ctb(LUA_VLNGSTR):
return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
default:
return gcvalue(k1) == gcvalueraw(keyval(n2));
@@ -251,11 +257,12 @@ static unsigned int setlimittosize (Table *t) {
/*
** "Generic" get version. (Not that generic: not valid for integers,
** which may be in array part, nor for floats with integral values.)
** See explanation about 'deadok' in function 'equalkey'.
*/
static const TValue *getgeneric (Table *t, const TValue *key) {
static const TValue *getgeneric (Table *t, const TValue *key, int deadok) {
Node *n = mainpositionTV(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
if (equalkey(key, n))
if (equalkey(key, n, deadok))
return gval(n); /* that's it */
else {
int nx = gnext(n);
@@ -292,7 +299,7 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key,
if (i - 1u < asize) /* is 'key' inside array part? */
return i; /* yes; that's the index */
else {
const TValue *n = getgeneric(t, key);
const TValue *n = getgeneric(t, key, 1);
if (unlikely(isabstkey(n)))
luaG_runerror(L, "invalid key to 'next'"); /* key not found */
i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */
@@ -730,7 +737,7 @@ const TValue *luaH_getstr (Table *t, TString *key) {
else { /* for long strings, use generic case */
TValue ko;
setsvalue(cast(lua_State *, NULL), &ko, key);
return getgeneric(t, &ko);
return getgeneric(t, &ko, 0);
}
}
@@ -750,7 +757,7 @@ const TValue *luaH_get (Table *t, const TValue *key) {
/* else... */
} /* FALLTHROUGH */
default:
return getgeneric(t, key);
return getgeneric(t, key, 0);
}
}