Don't assume a scalar Map/Set initializer is an integer if its not a string
commitf8f815d06f7b791a2f32dbb5552e4e2033b0ca8d
authorRick Lavoie <rlavoie@fb.com>
Wed, 1 Jul 2015 21:01:12 +0000 (1 14:01 -0700)
committerhhvm-bot <hhvm-bot@fb.com>
Wed, 1 Jul 2015 21:32:52 +0000 (1 14:32 -0700)
tree53fd01db43f84f5aa04f2e1d3d106ce08df3e638
parent54c7c88277f3044c8675565ef6a6bfd7ffcef5f7
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
hphp/compiler/analysis/emitter.cpp
hphp/test/slow/collection_classes/invalid-initializers.php [new file with mode: 0644]
hphp/test/slow/collection_classes/invalid-initializers.php.expect [new file with mode: 0644]