• Subject: Re: Numeric key collision related bug in Lua 5.3
• From: "Liam Devine" <liamdevine@...>
• Date: Tue, 21 Apr 2015 20:38:10 +0100

```On 21/04/15 17:36, Dirk Laurie wrote:
>
> 2015-04-21 17:32 GMT+02:00 Egor Skriptunoff <egor.skriptunoff@gmail.com>:
>> Hi!
>>
>> An interesting bug has been found in Lua 5.3
>>
>> t = {[(1<<63)-333] = 0}
>> key = next(t) + 0.0
>> t[key] = "Lua is great!"
>> print(t[key])          --> Lua is great!
>> t[0] = "Are you sure?"
>> print(t[key])          --> nil
>>
>> Why Lua is not great anymore?
>
> The manual says:
>
> The indexing of tables follows the definition of raw equality in the
> language. The expressions a[i] and a[j] denote the same table element
> if and only if i and j are raw equal (that is, equal without
> metamethods). In particular, floats with integral values are equal to
> their respective integers (e.g., 1.0 == 1). To avoid ambiguities, any
> float with integral value used as a key is converted to its respective
> integer. For instance, if you write a[2.0] = true, the actual key
> inserted into the table will be the integer 2. (On the other hand, 2
> and "2" are different Lua values and therefore denote different table
> entries.)
>
> Let origkey = 1<<63)-333, which  is a very large integer, but slightly
> smaller than math.maxinteger.
>
> "key" is a float with integral value, but that integral value is not
> origkey, but math.maxinteger. In a floating-point comparison, it tests
> equal to origkey,
> though.
>
> When t[key] is assigned, "key" is not considered to be a new index, and
> the value of t[origkey] is replaced.
>
> When t[0] is assigned, the hash part of the table is reorganized.
> t[origkey] is still "Lua is great!", but is no longer found when asking
> for t[key].
>

For me, there is a problem here and it seems to be with rawequal. What
does it mean to compare with rawequal? Well the manual says:

"Checks whether v1 is equal to v2, without invoking any metamethod.
Returns a boolean"

I think there is a standard definition of what equal means, but what
does it mean when you do not use a metamethod:

> return rawequal(1, 1)
true

> return rawequal(2.1, 2)
false

> return rawequal(2.1, 3.0)
false

OK it may seem a little silly but let us add max integer to the last one:

> return rawequal(math.maxinteger+2.1, math.maxinteger+3.0)
true

Hmm that doesn't seem very equal to me. As a consequence of this
equality you can not store more than one floating point number, as a
key, in a table when it is larger than maxinteger.

> t = {} for i = 1, 100 do t[math.maxinteger+(i+0.1)] = i end for k,v in
pairs(t) do print(k,v) end
9.2233720368548e+18	100

This is what the manual states about conversions:
Lua provides some automatic conversions between some types and
representations at run time. Bitwise operators always convert float
operands to integers. Exponentiation and float division always convert
integer operands to floats. All other arithmetic operations applied to
mixed numbers (integers and floats) convert the integer operand to a
float; this is called the usual rule. The C API also converts both
integers to floats and floats to integers, as needed.

So the "usaal rule" is not being used in rawequal, but the C API can do
as it likes when it is needed. Shouldn't rawequal explicitly state this
happens?

I would not have guessed that two floating point numbers greater than
maxinteger would ever compare equal when they are far enough apart to
detect a difference.

--
Liam

```

Attachment: signature.asc
Description: OpenPGP digital signature