Array.prototype.concat result length (ES5.1)

liorean liorean at gmail.com
Mon Jul 18 14:02:49 PDT 2011


> On 07/14/2011 10:04 AM, Allen Wirfs-Brock wrote:
>> It is probably a bug, because array index based operations generally warp
>> around to 0 at 2^32.

On 18 July 2011 19:51, Jeff Walden <jwalden+es at mit.edu> wrote:
> Removing all the RangeError stuff, and making array indexes just
> non-negative integers,  would be nice for ES6 or similar.  I suspect
> changing that won't break anyone worth caring about, although I do know some
> people have taken the time to care about this in the past (mostly in a
> spec-nut way :-) ):
>
> http://hexmen.com/blog/2006/12/push-and-pop/

Hmm. That link has the following to say:
-----
Steps 3 – 6 of push are a little ambiguous, and the specification
probably should have stated that repeated increments to n must be done
using 32-bit unsigned integer arithmetic – it’s kind-of implicit as n
is assigned the result of the internal ToUint32 operator. Using 32-bit
arithmetic leads to some strange edge-cases: when n overflows from
232-1 to 0, push will have set a property called 4294967295. This is
strange, as 429496795 is not an array index (as discussed above), but
at least it means the property-value will still be available after the
inevitable array-truncation (when length is set to some small value in
step 8.)
----

That is actually contrary to my reading of ECMA-262 3ed. intentions. I
assume 5 ed. has the same intentions, but I have not checked it. The
way I read those intentions is as you can see in the error I reported
in my comment to:
    http://blogs.msdn.com/b/jscript/archive/2008/03/25/performance-optimization-of-arrays-part-i.aspx
(Opera fixed a different but related bug in the same algorithms in
Futhark to follow the correct handling (as I read the spec). Carakan
today I don't know about.)

For those not wanting to go searching for my comment and sifting
through that text: The algorithm in question uses ToUInt32 to convert
the value, but the storage is not as uint32 but as pretty much
everywhere in ECMAScript, Number, thus follows normal double
arithmetics. This is particularly of note as it means that it should
not wrap around - the purpose of the following parts of 15.4.5.1
[[Put]] (P, V):
----
12. Compute ToUint32(V).

13. If Result(12) is not equal to ToNumber(V), throw a RangeError exception.

14. For every integer k that is less than the value of the length
property of A but not less than Result(12), if A itself has a property
(not an inherited property) named ToString(k), then delete that
property.

15. Set the value of property P of A to Result(12).
----
is to, at step 13, catch the specific event of trying to exceed uint32
size with the length property and throw an error *instead of* wrapping
around and as a result of step 14 of above algorithm destroy
properties on the array. Wrapping around is an error, because ToUInt32
gives not a uint32 but a Number which can fit into a unit32 as result.
IIRC the 3ed. spec never uses any other number format than Number, it
only performs the operations to fit an input Number type into the
limitations of those other number types, into an output of Number
type.
-- 
David "liorean" Andersson


More information about the es-discuss mailing list