diff options
Diffstat (limited to 'libs/liblua/src/ltable.c')
-rw-r--r-- | libs/liblua/src/ltable.c | 46 |
1 files changed, 30 insertions, 16 deletions
diff --git a/libs/liblua/src/ltable.c b/libs/liblua/src/ltable.c index 5a0d066faa..7e7cbed97c 100644 --- a/libs/liblua/src/ltable.c +++ b/libs/liblua/src/ltable.c @@ -166,17 +166,30 @@ static Node *mainpositionTV (const Table *t, const TValue *key) { /* -** Check whether key 'k1' is equal to the key in node 'n2'. -** This equality is raw, so there are no metamethods. Floats -** with integer values have been normalized, so integers cannot -** be equal to floats. It is assumed that 'eqshrstr' is simply -** pointer equality, so that short strings are handled in the -** default case. -*/ -static int equalkey (const TValue *k1, const Node *n2) { - if (rawtt(k1) != keytt(n2)) /* not the same variants? */ +** Check whether key 'k1' is equal to the key in node 'n2'. This +** equality is raw, so there are no metamethods. Floats with integer +** values have been normalized, so integers cannot 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. All dead keys are compared in the default case, by pointer +** identity. (Only collectable objects can produce dead keys.) Note that +** dead long strings are also compared by identity. +** Once a key is dead, its corresponding value may be collected, and +** then another value can be created with the same address. If this +** other value is given to 'next', 'equalkey' will signal a false +** positive. In a regular traversal, this situation should never happen, +** as all keys given to 'next' came from the table itself, and therefore +** could not have been collected. Outside a regular traversal, we +** have garbage in, garbage out. What is relevant is that this false +** positive does not break anything. (In particular, 'next' will return +** some other valid item on the table or nil.) +*/ +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 +200,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 +264,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 +306,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 +744,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 +764,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { /* else... */ } /* FALLTHROUGH */ default: - return getgeneric(t, key); + return getgeneric(t, key, 0); } } |