Don't assume a scalar Map/Set initializer is an integer if its not a string
Summary: HHVM incorrectly allows boolean and floating-point values to be specified in Map
and Set initializers (under certain conditions). IE, Set { true, false } and Map
{ true => 'a', false => 'b' } work, when they should throw an Invalid Argument
exception (just like all the other operations on collections when given booleans
or floats).
The root cause of this is that the bytecode emitter assumes that if a Map or Set
initializer is a scalar, and is not a string, it must be an integer. Under debug
builds, this causes assertions as it means a Variant of type bool or float is
accessed as an integer. Under most conditions, the bytecode emitter will
initialize the collection directly from an array, bypassing the checks in the
collection add method, therefore allowing these types into the collection. The
rest of the collection logic assumes that the contained values are either
integers or strings, possibly leading to odd results (the floating point values
are treated as integer versions of the bit representation of the float).
The fix is to explicitly check if the initializers are integers, and if not,
don't attempt the direct array initialization. Instead the collection
initialization which uses repeated calls to add() will be used, allowing for
proper checking.
Reviewed By: @binliu19, @markw65
Differential Revision:
D2202642